diff --git a/docs/make_index.py b/docs/make_index.py index 9c5415e47..a3ea386ba 100644 --- a/docs/make_index.py +++ b/docs/make_index.py @@ -76,7 +76,7 @@ def policy_param_text(pname, param): else: txt += '
Long Name: {}'.format(param['long_name']) txt += '
Description: {}'.format(param['description']) - if len(param['notes']) > 0: + if len(param.get('notes', '')) > 0: txt += '
Notes: {}'.format(param['notes']) txt += '
Has An Effect When Using:' txt += '   PUF data: ' @@ -118,8 +118,8 @@ def policy_param_text(pname, param): minval = param['valid_values']['min'] maxval = param['valid_values']['max'] txt += ' min = {} and max = {}'.format(minval, maxval) - txt += '
Out-of-Range Action: {}'.format( - param['invalid_action']) + invalid_action = param.get('invalid_action', 'stop') + txt += '
Out-of-Range Action: {}'.format(invalid_action) txt += '

' return txt diff --git a/new_json.py b/new_json.py new file mode 100644 index 000000000..7c3f7aa4e --- /dev/null +++ b/new_json.py @@ -0,0 +1,70 @@ +""" +Command-line tool that converts Tax-Calculator JSON reform/assumption file +from the old (1.x) format to the new (2.0) format. +------------------------------------------------------------------------ +WARNING: This program make certain assumptions about how the JSON file + is formatted, so it will not work correctly on a JSON file + that is not formatted in the assumed way. There is no risk + in trying it because a copy of the original JSON file is made. +------------------------------------------------------------------------ +""" +# CODING-STYLE CHECKS: +# pycodestyle new_json.py +# pylint --disable=locally-disabled new_json.py + +import os +import sys +import argparse +import shutil +import re + + +def main(): + """ + Contains high-level logic. + """ + # parse command-line argument: + usage_str = 'python new_json.py FILENAME [--help]' + parser = argparse.ArgumentParser( + prog='', + usage=usage_str, + description=('Converts old (1.x) JSON reform/assumption file ' + 'named FILENAME to new (2.0) format. The newly ' + 'formatted file is also called FILENAME, while ' + 'the old file is saved as FILENAME-old.') + ) + parser.add_argument('FILENAME', nargs='?', + help=('FILENAME is name of JSON-formatted file that ' + 'is to be converted.'), + default='') + args = parser.parse_args() + # check existence of FILENAME + if not os.path.isfile(args.FILENAME): + msg = 'ERROR: FILENAME={} does not exist'.format(args.FILENAME) + print(msg) + return 1 + # copy FILENAME to FILENAME-old + shutil.copyfile(args.FILENAME, '{}-old'.format(args.FILENAME)) + # read FILENAME into string + with open(args.FILENAME, 'r') as oldfile: + txt = oldfile.read() + # convert txt elements + defaults_file = (args.FILENAME == 'policy_current_law.json' or + args.FILENAME == 'consumption.json' or + args.FILENAME == 'growdiff.json') + if defaults_file: + txt = re.sub(r'(^\s*")_', r'\g<1>', txt, flags=re.MULTILINE) + else: + txt = re.sub(r'(\s*")_', r'\g<1>', txt, flags=re.MULTILINE) + txt = re.sub(r'\[([0-9tf\-])', r'\g<1>', txt, flags=re.MULTILINE) + txt = re.sub(r'([0-9e])\]', r'\g<1>', txt, flags=re.MULTILINE) + # write converted txt to FILENAME + with open(args.FILENAME, 'w') as newfile: + newfile.write(txt) + # normal return code + return 0 +# end of main function code + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/taxcalc/assumptions/economic_assumptions_template.json b/taxcalc/assumptions/economic_assumptions_template.json index 242963950..68ef2a6b4 100644 --- a/taxcalc/assumptions/economic_assumptions_template.json +++ b/taxcalc/assumptions/economic_assumptions_template.json @@ -7,71 +7,71 @@ // . { "consumption": { - "_MPC_e17500": {"2017": [0.0]}, - "_MPC_e18400": {"2017": [0.0]}, - "_MPC_e19800": {"2017": [0.0]}, - "_MPC_e20400": {"2017": [0.0]}, - "_BEN_housing_value": {"2017": [1.0]}, - "_BEN_snap_value": {"2017": [1.0]}, - "_BEN_tanf_value": {"2017": [1.0]}, - "_BEN_vet_value": {"2017": [1.0]}, - "_BEN_wic_value": {"2017": [1.0]}, - "_BEN_mcare_value": {"2017": [1.0]}, - "_BEN_mcaid_value": {"2017": [1.0]}, - "_BEN_other_value": {"2017": [1.0]} + "MPC_e17500": {"2017": 0.0}, + "MPC_e18400": {"2017": 0.0}, + "MPC_e19800": {"2017": 0.0}, + "MPC_e20400": {"2017": 0.0}, + "BEN_housing_value": {"2017": 1.0}, + "BEN_snap_value": {"2017": 1.0}, + "BEN_tanf_value": {"2017": 1.0}, + "BEN_vet_value": {"2017": 1.0}, + "BEN_wic_value": {"2017": 1.0}, + "BEN_mcare_value": {"2017": 1.0}, + "BEN_mcaid_value": {"2017": 1.0}, + "BEN_other_value": {"2017": 1.0} }, "growdiff_baseline": { - "_ABOOK": {"2017": [0.0]}, - "_ACGNS": {"2017": [0.0]}, - "_ACPIM": {"2017": [0.0]}, - "_ACPIU": {"2017": [0.0]}, - "_ADIVS": {"2017": [0.0]}, - "_AINTS": {"2017": [0.0]}, - "_AIPD": {"2017": [0.0]}, - "_ASCHCI": {"2017": [0.0]}, - "_ASCHCL": {"2017": [0.0]}, - "_ASCHEI": {"2017": [0.0]}, - "_ASCHEL": {"2017": [0.0]}, - "_ASCHF": {"2017": [0.0]}, - "_ASOCSEC": {"2017": [0.0]}, - "_ATXPY": {"2017": [0.0]}, - "_AUCOMP": {"2017": [0.0]}, - "_AWAGE": {"2017": [0.0]}, - "_ABENOTHER": {"2017": [0.0]}, - "_ABENMCARE": {"2017": [0.0]}, - "_ABENMCAID": {"2017": [0.0]}, - "_ABENSSI": {"2017": [0.0]}, - "_ABENSNAP": {"2017": [0.0]}, - "_ABENWIC": {"2017": [0.0]}, - "_ABENHOUSING": {"2017": [0.0]}, - "_ABENTANF": {"2017": [0.0]}, - "_ABENVET": {"2017": [0.0]} + "ABOOK": {"2017": 0.0}, + "ACGNS": {"2017": 0.0}, + "ACPIM": {"2017": 0.0}, + "ACPIU": {"2017": 0.0}, + "ADIVS": {"2017": 0.0}, + "AINTS": {"2017": 0.0}, + "AIPD": {"2017": 0.0}, + "ASCHCI": {"2017": 0.0}, + "ASCHCL": {"2017": 0.0}, + "ASCHEI": {"2017": 0.0}, + "ASCHEL": {"2017": 0.0}, + "ASCHF": {"2017": 0.0}, + "ASOCSEC": {"2017": 0.0}, + "ATXPY": {"2017": 0.0}, + "AUCOMP": {"2017": 0.0}, + "AWAGE": {"2017": 0.0}, + "ABENOTHER": {"2017": 0.0}, + "ABENMCARE": {"2017": 0.0}, + "ABENMCAID": {"2017": 0.0}, + "ABENSSI": {"2017": 0.0}, + "ABENSNAP": {"2017": 0.0}, + "ABENWIC": {"2017": 0.0}, + "ABENHOUSING": {"2017": 0.0}, + "ABENTANF": {"2017": 0.0}, + "ABENVET": {"2017": 0.0} }, "growdiff_response": { - "_ABOOK": {"2017": [0.0]}, - "_ACGNS": {"2017": [0.0]}, - "_ACPIM": {"2017": [0.0]}, - "_ACPIU": {"2017": [0.0]}, - "_ADIVS": {"2017": [0.0]}, - "_AINTS": {"2017": [0.0]}, - "_AIPD": {"2017": [0.0]}, - "_ASCHCI": {"2017": [0.0]}, - "_ASCHCL": {"2017": [0.0]}, - "_ASCHEI": {"2017": [0.0]}, - "_ASCHEL": {"2017": [0.0]}, - "_ASCHF": {"2017": [0.0]}, - "_ASOCSEC": {"2017": [0.0]}, - "_ATXPY": {"2017": [0.0]}, - "_AUCOMP": {"2017": [0.0]}, - "_AWAGE": {"2017": [0.0]}, - "_ABENOTHER": {"2017": [0.0]}, - "_ABENMCARE": {"2017": [0.0]}, - "_ABENMCAID": {"2017": [0.0]}, - "_ABENSSI": {"2017": [0.0]}, - "_ABENSNAP": {"2017": [0.0]}, - "_ABENWIC": {"2017": [0.0]}, - "_ABENHOUSING": {"2017": [0.0]}, - "_ABENTANF": {"2017": [0.0]}, - "_ABENVET": {"2017": [0.0]} + "ABOOK": {"2017": 0.0}, + "ACGNS": {"2017": 0.0}, + "ACPIM": {"2017": 0.0}, + "ACPIU": {"2017": 0.0}, + "ADIVS": {"2017": 0.0}, + "AINTS": {"2017": 0.0}, + "AIPD": {"2017": 0.0}, + "ASCHCI": {"2017": 0.0}, + "ASCHCL": {"2017": 0.0}, + "ASCHEI": {"2017": 0.0}, + "ASCHEL": {"2017": 0.0}, + "ASCHF": {"2017": 0.0}, + "ASOCSEC": {"2017": 0.0}, + "ATXPY": {"2017": 0.0}, + "AUCOMP": {"2017": 0.0}, + "AWAGE": {"2017": 0.0}, + "ABENOTHER": {"2017": 0.0}, + "ABENMCARE": {"2017": 0.0}, + "ABENMCAID": {"2017": 0.0}, + "ABENSSI": {"2017": 0.0}, + "ABENSNAP": {"2017": 0.0}, + "ABENWIC": {"2017": 0.0}, + "ABENHOUSING": {"2017": 0.0}, + "ABENTANF": {"2017": 0.0}, + "ABENVET": {"2017": 0.0} } } diff --git a/taxcalc/assumptions/simple_parameters_template.json b/taxcalc/assumptions/simple_parameters_template.json deleted file mode 100644 index 24dc50bf2..000000000 --- a/taxcalc/assumptions/simple_parameters_template.json +++ /dev/null @@ -1,10 +0,0 @@ -// Sample JSON parameter file suitable for Calculator.read_json_parameters(), -// which is a function used by other PSL models to read simple parameter -// schema that do not involve the use of [] brackets around parameter values -// and that do not involve parameter with vector values or parameters that are -// inflation indexed. -{ - "BE_sub": {"2018": -0.05, "2021": -0.25}, - "BE_inc": {"2020": 0.10}, - "BE_cg": {"2022": -0.70} -} diff --git a/taxcalc/calcfunctions.py b/taxcalc/calcfunctions.py index 21d5d03eb..995d06d95 100644 --- a/taxcalc/calcfunctions.py +++ b/taxcalc/calcfunctions.py @@ -3,7 +3,7 @@ These functions are imported into the Calculator class. -Note: the cpi_offset policy parameter is the only policy parameter that +Note: the CPI_offset policy parameter is the only policy parameter that does not appear here; it is used in the policy.py file to possibly adjust the price inflation rate used to index policy parameters (as would be done in a reform that introduces chained-CPI indexing). diff --git a/taxcalc/calculator.py b/taxcalc/calculator.py index af8eed634..45fbac729 100644 --- a/taxcalc/calculator.py +++ b/taxcalc/calculator.py @@ -1099,7 +1099,7 @@ def read_json_param_objects(reform, assump): suitable as input into the GrowDiff.update_growdiff method. """ # pylint: disable=too-many-branches - # first process second assump parameter + # first process the second assump argument if assump is None: cons_dict = dict() gdiff_base_dict = dict() @@ -1124,7 +1124,7 @@ def read_json_param_objects(reform, assump): gdiff_resp_dict) = Calculator._read_json_econ_assump_text(txt) else: raise ValueError('assump is neither None nor string') - # next process first reform parameter + # next process the first reform argument if reform is None: rpol_dict = dict() elif isinstance(reform, str): @@ -1157,13 +1157,13 @@ def read_json_param_objects(reform, assump): @staticmethod def reform_documentation(params, policy_dicts=None): """ - Generate reform documentation. + Generate reform documentation versus current-law policy. Parameters ---------- params: dict dictionary is structured like dict returned from - the static Calculator method read_json_param_objects() + the static Calculator.read_json_param_objects() method policy_dicts : list of dict or None each dictionary in list is a params['policy'] dictionary @@ -1174,19 +1174,18 @@ def reform_documentation(params, policy_dicts=None): Returns ------- doc: String - the documentation for the policy reform specified in params + the documentation for the specified policy reform """ - # pylint: disable=too-many-statements,too-many-branches + # pylint: disable=too-many-statements,too-many-branches,too-many-locals - # nested function used only in reform_documentation - def param_doc(years, change, base): + # nested function used only in reform_documentation function + def param_doc(years_list, updated, baseline): """ Parameters ---------- - years: list of change years - change: dictionary of parameter changes - base: Policy or GrowDiff object with baseline values - syear: parameter start calendar year + years_list: list of parameter-change years + updated: reform Policy or updated GrowDiff object + base: current-law Policy or default GrowDiff object Returns ------- @@ -1223,102 +1222,129 @@ def lines(text, num_indent_spaces, max_line_length=77): line_list.append(line) return line_list - # begin main logic of param_doc + # begin main logic of nested function param_doc # pylint: disable=too-many-nested-blocks - assert len(years) == len(change.keys()) - basex = copy.deepcopy(base) - basevals = getattr(basex, '_vals', None) - assert isinstance(basevals, dict) doc = '' + assert isinstance(years_list, list) + years = sorted(years_list) for year in years: - # write year - basex.set_year(year) - doc += '{}:\n'.format(year) - # write info for each param in year - for param in sorted(change[year].keys()): - # ... write param:value line - pval = change[year][param] - if isinstance(pval, list): - pval = pval[0] - if basevals[param]['value_type'] == 'boolean': + baseline.set_year(year) + updated.set_year(year) + mdata_base = baseline.metadata() + mdata_upda = updated.metadata() + mdata_base_keys = mdata_base.keys() + mdata_upda_keys = mdata_upda.keys() + assert set(mdata_base_keys) == set(mdata_upda_keys) + params_with_diff = list() + for pname in mdata_base_keys: + base_value = mdata_base[pname]['value'] + upda_value = mdata_upda[pname]['value'] + if upda_value != base_value: + params_with_diff.append(pname) + if params_with_diff: + # write year + doc += '{}:\n'.format(year) + for pname in sorted(params_with_diff): + # write updated value line + pval = mdata_upda[pname]['value'] + if mdata_base[pname]['value_type'] == 'boolean': if isinstance(pval, list): pval = [bool(item) for item in pval] else: pval = bool(pval) - doc += ' {} : {}\n'.format(param, pval) - # ... write optional param-index line - if isinstance(pval, list): - pval = basevals[param]['col_label'] - pval = [str(item) for item in pval] - doc += ' ' * (4 + len(param)) + '{}\n'.format(pval) - # ... write name line - if param.endswith('_cpi'): - rootparam = param[:-4] - name = '{} inflation indexing status'.format(rootparam) - else: - name = basevals[param]['long_name'] - for line in lines('name: ' + name, 6): - doc += ' ' + line - # ... write optional desc line - if not param.endswith('_cpi'): - desc = basevals[param]['description'] + doc += ' {} : {}\n'.format(pname, pval) + # ... write optional param-vector-index line + if isinstance(pval, list): + pval = mdata_base[pname].get('vi_vals', []) + pval = [str(item) for item in pval] + doc += ' ' * (4 + len(pname)) + '{}\n'.format(pval) + # ... write param-name line + name = mdata_base[pname]['long_name'] + for line in lines('name: ' + name, 6): + doc += ' ' + line + # ... write param-description line + desc = mdata_base[pname]['description'] for line in lines('desc: ' + desc, 6): doc += ' ' + line - # ... write baseline_value line - if isinstance(basex, Policy): - if param.endswith('_cpi'): - rootparam = param[:-4] - bval = basevals[rootparam].get('indexed', False) - else: - bval = getattr(basex, param[1:], None) - if isinstance(bval, np.ndarray): - bval = bval.tolist() - if basevals[param]['value_type'] == 'boolean': - bval = [bool(item) for item in bval] - elif basevals[param]['value_type'] == 'boolean': - bval = bool(bval) - doc += ' baseline_value: {}\n'.format(bval) - else: # if basex is GrowDiff object - # all GrowDiff parameters have zero as default value - doc += ' baseline_value: 0.0\n' + # ... write param-baseline-value line + if isinstance(baseline, Policy): + pval = mdata_base[pname]['value'] + ptype = mdata_base[pname]['value_type'] + if isinstance(pval, list): + if ptype == 'boolean': + pval = [bool(item) for item in pval] + elif ptype == 'boolean': + pval = bool(pval) + doc += ' baseline_value: {}\n'.format(pval) + else: # if baseline is GrowDiff object + # each GrowDiff parameter has zero as default value + doc += ' baseline_value: 0.0\n' + del mdata_base + del mdata_upda + del mdata_base_keys + del mdata_upda_keys return doc # begin main logic of reform_documentation - # create Policy object with pre-reform (i.e., baseline) values - # ... create gdiff_baseline object - gdb = GrowDiff() - gdb.update_growdiff(params['growdiff_baseline']) - # ... create GrowFactors object that will incorporate gdiff_baseline + # create Policy object with current-law-policy values + gdiff_base = GrowDiff() + gdiff_base.update_growdiff(params['growdiff_baseline']) gfactors_clp = GrowFactors() - gdb.apply_to(gfactors_clp) - # ... create Policy object containing pre-reform parameter values + gdiff_base.apply_to(gfactors_clp) clp = Policy(gfactors=gfactors_clp) + # create Policy object with post-reform values + gdiff_resp = GrowDiff() + gdiff_resp.update_growdiff(params['growdiff_response']) + gfactors_ref = GrowFactors() + gdiff_base.apply_to(gfactors_ref) + gdiff_resp.apply_to(gfactors_ref) + ref = Policy(gfactors=gfactors_ref) + ref.implement_reform(params['policy']) + reform_years = Policy.years_in_revision(params['policy']) + if policy_dicts is not None: # compound reform has been specified + assert isinstance(policy_dicts, list) + for policy_dict in policy_dicts: + ref.implement_reform(policy_dict) + xyears = Policy.years_in_revision(policy_dict) + for year in xyears: + if year not in reform_years: + reform_years.append(year) # generate documentation text doc = 'REFORM DOCUMENTATION\n' + # ... documentation for baseline growdiff assumptions doc += 'Baseline Growth-Difference Assumption Values by Year:\n' - years = sorted(params['growdiff_baseline'].keys()) + years = GrowDiff.years_in_revision(params['growdiff_baseline']) if years: - doc += param_doc(years, params['growdiff_baseline'], gdb) + doc += param_doc(years, gdiff_base, GrowDiff()) else: - doc += 'none: using default baseline growth assumptions\n' - doc += 'Policy Reform Parameter Values by Year:\n' - years = sorted(params['policy'].keys()) + doc += 'none: using default growth assumptions\n' + # ... documentation for reform growdiff assumptions + doc += 'Response Growth-Difference Assumption Values by Year:\n' + years = GrowDiff.years_in_revision(params['growdiff_response']) if years: - doc += param_doc(years, params['policy'], clp) + doc += param_doc(years, gdiff_resp, GrowDiff()) + else: + doc += 'none: using default growth assumptions\n' + # ... documentation for (possibly compound) policy reform + if policy_dicts is None: + doc += 'Policy Reform Parameter Values by Year:\n' + else: + doc += 'Compound Policy Reform Parameter Values by Year:\n' + # ... use clp and ref Policy objects to generate documentation + if reform_years: + doc += param_doc(reform_years, ref, clp) else: doc += 'none: using current-law policy parameters\n' - if policy_dicts is not None: - assert isinstance(policy_dicts, list) - base = clp - base.implement_reform(params['policy']) - assert not base.parameter_errors - for policy_dict in policy_dicts: - assert isinstance(policy_dict, dict) - doc += 'Policy Reform Parameter Values by Year:\n' - years = sorted(policy_dict.keys()) - doc += param_doc(years, policy_dict, base) - base.implement_reform(policy_dict) - assert not base.parameter_errors + # cleanup local objects + del gdiff_base + del gfactors_clp + del gdiff_resp + del gfactors_ref + del clp + del ref + del years + del reform_years + # return documentation string return doc def ce_aftertax_income(self, calc, @@ -1461,29 +1487,29 @@ def _read_json_policy_reform_text(text_string): """ Strip //-comments from text_string and return 1 dict based on the JSON. - Specified text is JSON with at least 1 high-level key:object pair: + Specified text is JSON with 1 high-level key:object pair: a "policy": {...} pair. Other keys such as "consumption", "growdiff_baseline", or "growdiff_response" will raise a ValueError. The {...} object may be empty (that is, be {}), or - may contain one or more pairs with parameter string primary keys - and string years as secondary keys. See tests/test_calculator.py for - an extended example of a commented JSON policy reform text - that can be read by this method. + may contain one or more pairs with parameter string primary keys and + string years as secondary keys. See test_json_reform_url() in the + tests/test_calculator.py for an extended example of a commented JSON + policy reform text that can be read by this method. - Returned dictionary prdict has integer years as primary keys and - string parameters as secondary keys. This returned dictionary is - suitable as the argument to the Policy implement_reform(prdict) method. + Returned dictionaries pr_dict has string parameters as primary keys and + integer years as secondary keys (that is, they have a param:year:value + format). These returned dictionaries are suitable as the arguments to + the Policy.implement_reform(pr_dict) method. """ - # pylint: disable=too-many-locals # strip out //-comments without changing line numbers json_str = re.sub('//.*', ' ', text_string) # convert JSON text into a Python dictionary - raw_dict = json_to_dict(json_str) + full_dict = json_to_dict(json_str) # check key contents of dictionary - actual_keys = set(raw_dict.keys()) + actual_keys = set(full_dict.keys()) missing_keys = Calculator.REQUIRED_REFORM_KEYS - actual_keys if missing_keys: msg = 'required key(s) "{}" missing from policy reform file' @@ -1492,16 +1518,15 @@ def _read_json_policy_reform_text(text_string): if illegal_keys: msg = 'illegal key(s) "{}" in policy reform file' raise ValueError(msg.format(illegal_keys)) - # convert raw_dict['policy'] dictionary into prdict - prdict = Calculator._convert_parameter_dict(raw_dict['policy']) - return prdict + # return the converted full_dict['policy'] dictionary + return Calculator._convert_year_to_int(full_dict['policy']) @staticmethod def _read_json_econ_assump_text(text_string): """ - Strip //-comments from text_string and return 5 dict based on the JSON. + Strip //-comments from text_string and return 3 dict based on the JSON. - Specified text is JSON with at least 5 high-level key:value pairs: + Specified text is JSON with 3 high-level key:value pairs: a "consumption": {...} pair, a "growdiff_baseline": {...} pair, and a "growdiff_response": {...} pair. @@ -1509,29 +1534,24 @@ def _read_json_econ_assump_text(text_string): Other keys such as "policy" will raise a ValueError. The {...} object may be empty (that is, be {}), or - may contain one or more pairs with parameter string primary keys - and string years as secondary keys. See tests/test_calculator.py for - an extended example of a commented JSON economic assumption text - that can be read by this method. - - Note that an example is shown in the ASSUMP_CONTENTS string in - the tests/test_calculator.py file. + may contain one or more pairs with parameter string primary keys and + string years as secondary keys. See test_json_assump_url() in the + tests/test_calculator.py for an extended example of a commented JSON + economic assumption text that can be read by this method. Returned dictionaries (cons_dict, gdiff_baseline_dict, - gdiff_respose_dict) have integer years as primary - keys and string parameters as secondary keys. - - These returned dictionaries are suitable as the arguments to + gdiff_respose_dict) have string parameters as primary keys and + integer years as secondary keys (that is, they have a param:year:value + format). These returned dictionaries are suitable as the arguments to the Consumption.update_consumption(cons_dict) method, or the GrowDiff.update_growdiff(gdiff_dict) method. """ - # pylint: disable=too-many-locals # strip out //-comments without changing line numbers json_str = re.sub('//.*', ' ', text_string) # convert JSON text into a Python dictionary - raw_dict = json_to_dict(json_str) + full_dict = json_to_dict(json_str) # check key contents of dictionary - actual_keys = set(raw_dict.keys()) + actual_keys = set(full_dict.keys()) missing_keys = Calculator.REQUIRED_ASSUMP_KEYS - actual_keys if missing_keys: msg = 'required key(s) "{}" missing from economic assumption file' @@ -1540,54 +1560,29 @@ def _read_json_econ_assump_text(text_string): if illegal_keys: msg = 'illegal key(s) "{}" in economic assumption file' raise ValueError(msg.format(illegal_keys)) - # convert the assumption dictionaries in raw_dict - key = 'consumption' - cons_dict = Calculator._convert_parameter_dict(raw_dict[key]) - key = 'growdiff_baseline' - gdiff_base_dict = Calculator._convert_parameter_dict(raw_dict[key]) - key = 'growdiff_response' - gdiff_resp_dict = Calculator._convert_parameter_dict(raw_dict[key]) - return (cons_dict, gdiff_base_dict, gdiff_resp_dict) + # return the converted assumption dictionaries in full_dict as a tuple + return ( + Calculator._convert_year_to_int(full_dict['consumption']), + Calculator._convert_year_to_int(full_dict['growdiff_baseline']), + Calculator._convert_year_to_int(full_dict['growdiff_response']) + ) @staticmethod - def _convert_parameter_dict(param_key_dict): - """ - Converts specified param_key_dict into a dictionary whose primary - keys are calendar years, and hence, is suitable as the argument to - the Policy.implement_reform() method, or - the Consumption.update_consumption() method, or - the GrowDiff.update_growdiff() method. - - Specified input dictionary has string parameter primary keys and - string years as secondary keys. - - Returned dictionary has integer years as primary keys and - string parameters as secondary keys. - """ - # convert year skey strings into integers - year_param = dict() - for pkey, sdict in param_key_dict.items(): - if not isinstance(pkey, str): - msg = 'pkey {} in param JSON is not a string' - raise ValueError(msg.format(pkey)) - rdict = dict() - if not isinstance(sdict, dict): - msg = 'pkey {} in param JSON is not paired with a dict' - raise ValueError(msg.format(pkey)) + def _convert_year_to_int(syr_dict): + """ + Converts specified syr_dict, which has string years as secondary + keys, into a dictionary with the same structure but having integer + years as secondary keys. + """ + iyr_dict = dict() + for pkey, sdict in syr_dict.items(): + assert isinstance(pkey, str) + assert pkey not in iyr_dict # will catch duplicate primary keys + iyr_dict[pkey] = dict() + assert isinstance(sdict, dict) for skey, val in sdict.items(): - if not isinstance(skey, str): - msg = 'skey {} in param JSON is not a string' - raise ValueError(msg.format(skey)) + assert isinstance(skey, str) year = int(skey) - rdict[year] = val - year_param[pkey] = rdict - # convert year_param dictionary to year_key_dict dictionary - year_key_dict = dict() - years = set() - for param, sdict in year_param.items(): - for year, val in sdict.items(): - if year not in years: - years.add(year) - year_key_dict[year] = dict() - year_key_dict[year][param] = val - return year_key_dict + assert year not in iyr_dict[pkey] # will catch duplicate years + iyr_dict[pkey][year] = val + return iyr_dict diff --git a/taxcalc/consumption.json b/taxcalc/consumption.json index fa180829a..43bea766b 100644 --- a/taxcalc/consumption.json +++ b/taxcalc/consumption.json @@ -1,208 +1,112 @@ { - "_MPC_e17500": { + "MPC_e17500": { "long_name": "Marginal propensity to consume medical expenses", "description": "Defined as dollar change in medical-expense consumption divided by dollar change in income. Typical value is in [0,1] range.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_MPC_e18400": { + "MPC_e18400": { "start_year": 2013, "long_name": "Marginal propensity to consume state-and-local taxes", "description": "Defined as dollar change in state-and-local-taxes consumption divided by dollar change in income. Typical value is in [0,1] range.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_MPC_e19800": { + "MPC_e19800": { "start_year": 2013, "long_name": "Marginal propensity to consume charity cash contributions", "description": "Defined as dollar change in charity-cash-contribution consumption divided by dollar change in income. Typical value is in [0,1] range.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_MPC_e20400": { + "MPC_e20400": { "start_year": 2013, "long_name": "Marginal propensity to consume miscellaneous deduction expenses", "description": "Defined as dollar change in miscellaneous-deduction-expense consumption divided by dollar change in income. Typical value is in [0,1] range.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_BEN_housing_value": { + "BEN_housing_value": { "long_name": "Consumption value of housing benefits", "description": "Consumption value per dollar of housing benefits, all of which are in-kind benefits.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_BEN_snap_value": { + "BEN_snap_value": { "long_name": "Consumption value of SNAP benefits", "description": "Consumption value per dollar of SNAP benefits, all of which are in-kind benefits.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_BEN_tanf_value": { + "BEN_tanf_value": { "long_name": "Consumption value of TANF benefits", "description": "Consumption value per dollar of TANF benefits, some of which are cash benefits and some of which are in-kind benefits.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_BEN_vet_value": { + "BEN_vet_value": { "long_name": "Consumption value of veterans benefits", "description": "Consumption value per dollar of veterans benefits, some of which are in-kind benefits (only about 48% are cash benefits).", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 2}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 2} }, - "_BEN_wic_value": { + "BEN_wic_value": { "long_name": "Consumption value of WIC benefits", "description": "Consumption value per dollar of WIC benefits, all of which are in-kind benefits.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} }, - "_BEN_mcare_value": { + "BEN_mcare_value": { "long_name": "Consumption value of Medicare benefits", "description": "Consumption value per dollar of Medicare benefits, all of which are in-kind benefits.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 2}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 2} }, - "_BEN_mcaid_value": { + "BEN_mcaid_value": { "long_name": "Consumption value of Medicaid benefits", "description": "Consumption value per dollar of Medicaid benefits, all of which are in-kind benefits.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 2}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 2} }, - "_BEN_other_value": { + "BEN_other_value": { "long_name": "Consumption value of other benefits", "description": "Consumption value per dollar of other benefits, some of which are in-kind benefits (somewhere between 52% and 76% are in-kind benefits).", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [1.0], - "valid_values": {"min": 0, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": 0, "max": 1} } } diff --git a/taxcalc/consumption.py b/taxcalc/consumption.py index 164120042..815fcc676 100644 --- a/taxcalc/consumption.py +++ b/taxcalc/consumption.py @@ -36,62 +36,14 @@ def __init__(self): super().__init__() self.initialize(Consumption.JSON_START_YEAR, Consumption.DEFAULT_NUM_YEARS) - self.parameter_warnings = '' - self.parameter_errors = '' def update_consumption(self, revision, print_warnings=True, raise_errors=True): """ - Update consumption for given revision, a dictionary consisting - of one or more year:modification dictionaries. - For example: {2014: {'_MPC_xxx': [0.2, 0.1]}} - - Note that this method uses the specified revision to update the - default MPC parameter values and the default BEN parameter values, - so use this method just once rather than calling it sequentially - in an attempt to update the parameters in several steps. + Update consumption default values using specified revision dictionary. + (see Parameters._update for argument documentation.) """ - if not isinstance(revision, dict): - raise ValueError('ERROR: revision is not a dictionary') - if not revision: - return # no revision to update - precall_current_year = self.current_year - self._set_default_vals() - # check that revisions keys are integers - revision_years = sorted(list(revision.keys())) - for year in revision_years: - if not isinstance(year, int): - msg = 'ERROR: {} KEY {}' - details = 'KEY in revision is not an integer calendar year' - raise ValueError(msg.format(year, details)) - # check range of revision_years - first_revision_year = min(revision_years) - if first_revision_year < self.start_year: - msg = 'ERROR: {} YEAR revision provision in YEAR < start_year={}' - raise ValueError(msg.format(first_revision_year, self.start_year)) - last_revision_year = max(revision_years) - if last_revision_year > self.end_year: - msg = 'ERROR: {} YEAR revision provision in YEAR > end_year={}' - raise ValueError(msg.format(last_revision_year, self.end_year)) - # validate revision parameter names and types - self.parameter_warnings = '' - self.parameter_errors = '' - self._validate_names_types(revision) - if self.parameter_errors: - raise ValueError(self.parameter_errors) - # implement the revision year by year - revision_parameters = set() - for year in revision_years: - self.set_year(year) - revision_parameters.update(revision[year].keys()) - self._update({year: revision[year]}) - self.set_year(precall_current_year) - # validate revision parameter values - self._validate_values(revision_parameters) - if self.parameter_warnings and print_warnings: - print(self.parameter_warnings) # pragma: no cover - if self.parameter_errors and raise_errors: - raise ValueError('\n' + self.parameter_errors) + self._update(revision, print_warnings, raise_errors) RESPONSE_VARS = set(['e17500', 'e18400', 'e19800', 'e20400']) BENEFIT_VARS = set(['housing', 'snap', 'tanf', 'vet', 'wic', diff --git a/taxcalc/growdiff.json b/taxcalc/growdiff.json index f7109db84..5cd6faf70 100644 --- a/taxcalc/growdiff.json +++ b/taxcalc/growdiff.json @@ -1,433 +1,233 @@ { - "_ABOOK": { + "ABOOK": { "long_name": "ABOOK additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABOOK extrapolates input variables: e07300 and e07400.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ACGNS": { + "ACGNS": { "long_name": "ACGNS additive difference from default projection", "description": "Default projection is in growfactors.csv file. ACGNS extrapolates input variables: e01200, p22250, p23250, e24515 and e24518.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ACPIM": { + "ACPIM": { "long_name": "ACPIM additive difference from default projection", "description": "Default projection is in growfactors.csv file. ACPIM extrapolates input variables: e03270, e03290 and e17500.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ACPIU": { + "ACPIU": { "long_name": "ACPIU additive difference from default projection", "description": "Default projection is in growfactors.csv file. ACPIU is the price inflation rate used to inflate many policy parameters. Note that non-zero values of this parameter will not affect historically known values of policy parameters.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ADIVS": { + "ADIVS": { "long_name": "ADIVS additive difference from default projection", "description": "Default projection is in growfactors.csv file. ADIVS extrapolates input variables: e00600 and e00650.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_AINTS": { + "AINTS": { "long_name": "AINTS additive difference from default projection", "description": "Default projection is in growfactors.csv file. AINTS extrapolates input variables: e00300 and e00400.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_AIPD": { + "AIPD": { "long_name": "AIPD additive difference from default projection", "description": "Default projection is in growfactors.csv file. AIPD extrapolates input variables: e19200.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ASCHCI": { + "ASCHCI": { "long_name": "ASCHCI additive difference from default projection", "description": "Default projection is in growfactors.csv file. ASCHCI extrapolates input variables: e00900, e00900p and e00900s when they are positive.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ASCHCL": { + "ASCHCL": { "long_name": "ASCHCL additive difference from default projection", "description": "Default projection is in growfactors.csv file. ASCHCL extrapolates input variables: e00900, e00900p and e00900s when they are negative.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ASCHEI": { + "ASCHEI": { "long_name": "ASCHEI additive difference from default projection", "description": "Default projection is in growfactors.csv file. ASCHEI extrapolates input variables: e02000 when positive, and e26270, k1bx14p, k1bx14s and e27200 for all values.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ASCHEL": { + "ASCHEL": { "long_name": "ASCHEL additive difference from default projection", "description": "Default projection is in growfactors.csv file. ASCHEL extrapolates input variable: e02000 when negative.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ASCHF": { + "ASCHF": { "long_name": "ASCHF additive difference from default projection", "description": "Default projection is in growfactors.csv file. ASCHF extrapolates input variables: e02100, e02100p and e02100s.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ASOCSEC": { + "ASOCSEC": { "long_name": "ASOCSEC additive difference from default projection", "description": "Default projection is in growfactors.csv file. ASOCSEC extrapolates input variable: e02400.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ATXPY": { + "ATXPY": { "long_name": "ATXPY additive difference from default projection", "description": "Default projection is in growfactors.csv file. ATXPY extrapolates input variables: e00700, e00800, e01400, e01500, e01700, e03150, e03210, e03220, e03230, e03300, e03400, e03500, e07240, e07260, p08000, e09700, e09800, e09900, e11200, e18400, e18500, e19800, e20100, e20400, g20500, e07600, e32800, e58990, e62900, e87530, e87521 and cmbtp.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_AUCOMP": { + "AUCOMP": { "long_name": "AUCOMP additive difference from default projection", "description": "Default projection is in growfactors.csv file. AUCOMP extrapolates input variable: e02300.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_AWAGE": { + "AWAGE": { "long_name": "AWAGE additive difference from default projection", "description": "Default projection is in growfactors.csv file. AWAGE extrapolates input variables: e00200, e00200p and e00200s. Also, AWAGE is the wage growth rate used to inflate the OASDI maximum taxable earnings policy parameter, _SS_Earnings_c. Note that non-zero values of this parameter will not affect historically known values of _SS_Earnings_c.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENOTHER": { + "ABENOTHER": { "long_name": "ABENOTHER additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENOTHER extrapolates input variable other_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENMCARE": { + "ABENMCARE": { "long_name": "ABENMCARE additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENMCARE extrapolates input variable mcare_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENMCAID": { + "ABENMCAID": { "long_name": "ABENMCAID additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENMCAID extrapolates input variable mcaid_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENSSI": { + "ABENSSI": { "long_name": "ABENSSI additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENSSI extrapolates input variable ssi_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENSNAP": { + "ABENSNAP": { "long_name": "ABENSNAP additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENSNAP extrapolates input variable snap_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENWIC": { + "ABENWIC": { "long_name": "ABENWIC additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENWIC extrapolates input variable wic_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENHOUSING": { + "ABENHOUSING": { "long_name": "ABENHOUSING additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENHOUSING extrapolates input variable housing_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENTANF": { + "ABENTANF": { "long_name": "ABENTANF additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENTANF extrapolates input variable tanf_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} }, - "_ABENVET": { + "ABENVET": { "long_name": "ABENVET additive difference from default projection", "description": "Default projection is in growfactors.csv file. ABENVET extrapolates input variable vet_ben.", - "section_1": "", - "section_2": "", - "notes": "", - "row_label": ["2013"], - "col_var": "", - "col_label": "", "value_type": "real", + "value_yrs": [2013], "value": [0.0], - "valid_values": {"min": -1, "max": 1}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" + "valid_values": {"min": -1, "max": 1} } } diff --git a/taxcalc/growdiff.py b/taxcalc/growdiff.py index ddae4ad77..7a5a873e8 100644 --- a/taxcalc/growdiff.py +++ b/taxcalc/growdiff.py @@ -34,57 +34,14 @@ def __init__(self): super().__init__() self.initialize(GrowDiff.JSON_START_YEAR, GrowDiff.DEFAULT_NUM_YEARS) - self.parameter_warnings = '' - self.parameter_errors = '' def update_growdiff(self, revision, print_warnings=True, raise_errors=True): """ - Update growdiff default values using specified revision, which is - a dictionary containing one or more year:modification dictionaries. - For example: {2014: {'_AWAGE': [0.01]}}. + Update growdiff default values using specified revision dictionary. + (see Parameters._update for argument documentation.) """ - if not isinstance(revision, dict): - raise ValueError('ERROR: revision is not a dictionary') - if not revision: - return # no revision to update - precall_current_year = self.current_year - self._set_default_vals() - # check that revisions keys are integers - revision_years = sorted(list(revision.keys())) - for year in revision_years: - if not isinstance(year, int): - msg = 'ERROR: {} KEY {}' - details = 'KEY in revision is not an integer calendar year' - raise ValueError(msg.format(year, details)) - # check range of revision_years - first_revision_year = min(revision_years) - if first_revision_year < self.start_year: - msg = 'ERROR: {} YEAR revision provision in YEAR < start_year={}' - raise ValueError(msg.format(first_revision_year, self.start_year)) - last_revision_year = max(revision_years) - if last_revision_year > self.end_year: - msg = 'ERROR: {} YEAR revision provision in YEAR > end_year={}' - raise ValueError(msg.format(last_revision_year, self.end_year)) - # validate revision parameter names and types - self.parameter_warnings = '' - self.parameter_errors = '' - self._validate_names_types(revision) - if self.parameter_errors: - raise ValueError(self.parameter_errors) - # implement the revision year by year - revision_parameters = set() - for year in revision_years: - self.set_year(year) - revision_parameters.update(revision[year].keys()) - self._update({year: revision[year]}) - self.set_year(precall_current_year) - # validate revision parameter values - self._validate_values(revision_parameters) - if self.parameter_warnings and print_warnings: - print(self.parameter_warnings) # pragma: no cover - if self.parameter_errors and raise_errors: - raise ValueError('\n' + self.parameter_errors) + self._update(revision, print_warnings, raise_errors) def has_any_response(self): """ diff --git a/taxcalc/parameters.py b/taxcalc/parameters.py index e17c88635..305434d20 100644 --- a/taxcalc/parameters.py +++ b/taxcalc/parameters.py @@ -9,6 +9,7 @@ import os import abc +from collections import OrderedDict import numpy as np from taxcalc.utils import read_egg_json, json_to_dict @@ -20,6 +21,8 @@ class Parameters(): Override this __init__ method and DEFAULTS_FILE_NAME and DEFAULTS_FILE_PATH in the inheriting class. """ + # pylint: disable=too-many-instance-attributes + __metaclass__ = abc.ABCMeta DEFAULTS_FILE_NAME = None @@ -34,25 +37,58 @@ def __init__(self): if os.path.isfile(file_path): with open(file_path) as pfile: json_text = pfile.read() - self._vals = json_to_dict(json_text) + vals = json_to_dict(json_text) else: # find file in conda package - self._vals = read_egg_json( - self.DEFAULTS_FILE_NAME) # pragma: no cover - - def initialize(self, start_year, num_years, wage_indexed_params=None): + vals = read_egg_json(self.DEFAULTS_FILE_NAME) # pragma: no cover + # add leading underscore character to each parameter name + self._vals = OrderedDict() + for pname in vals: + self._vals['_' + pname] = vals[pname] + del vals + # declare parameter warning/error variables + self.parameter_warnings = '' + self.parameter_errors = '' + + def initialize(self, start_year, num_years, last_known_year=None, + removed=None, redefined=None, wage_indexed=None): """ Called from subclass __init__ function. """ + # pylint: disable=too-many-arguments + # check arguments + assert start_year >= 0 + assert num_years >= 1 + end_year = start_year + num_years - 1 + assert last_known_year is None or isinstance(last_known_year, int) + assert removed is None or isinstance(removed, dict) + assert redefined is None or isinstance(redefined, dict) + assert wage_indexed is None or isinstance(wage_indexed, list) + # remember arguments self._current_year = start_year self._start_year = start_year self._num_years = num_years - self._end_year = start_year + num_years - 1 - if wage_indexed_params is None: - wage_indexed_param_list = list() + self._end_year = end_year + if last_known_year is None: + self._last_known_year = start_year + else: + assert last_known_year >= start_year + assert last_known_year <= end_year + self._last_known_year = last_known_year + if removed is None: + self._removed = dict() + else: + self._removed = removed + if redefined is None: + self._redefined = dict() + else: + self._redefined = redefined + if wage_indexed is None: + self._wage_indexed = list() else: - assert isinstance(wage_indexed_params, list) - wage_indexed_param_list = wage_indexed_params - self._set_default_vals(wage_indexed_params=wage_indexed_param_list) + self._wage_indexed = wage_indexed + # set default parameter values + self._apply_cpi_offset_to_inflation_rates() + self._set_default_vals() def inflation_rates(self): """ @@ -89,10 +125,17 @@ def start_year(self): """ return self._start_year + @property + def last_known_year(self): + """ + Parameters class last known parameter year property. + """ + return self._last_known_year + @property def end_year(self): """ - Parameters class lasst parameter year property. + Parameters class last parameter year property. """ return self._end_year @@ -123,18 +166,50 @@ def set_year(self, year): arr = getattr(self, name) setattr(self, name[1:], arr[iyr]) + def metadata(self): + """ + Returns ordered dictionary of all parameter information based on + DEFAULTS_FILE_NAME contents with each parameter's 'start_year', + 'value_yrs', and 'value' key values updated so that they contain + just the current_year information. + """ + mdata = OrderedDict() + for pname, pdata in self._vals.items(): + name = pname[1:] + mdata[name] = pdata + mdata[name]['start_year'] = '{}'.format(self.current_year) + mdata[name]['value_yrs'] = ['{}'.format(self.current_year)] + valraw = getattr(self, name) + if isinstance(valraw, np.ndarray): + val = valraw.tolist() + else: + val = valraw + mdata[name]['value'] = val + return mdata + + @staticmethod + def years_in_revision(revision): + """ + Return list of years in specified revision dictionary, which is + assumed to have a param:year:value format. + """ + assert isinstance(revision, dict) + years = list() + for _, paramdata in revision.items(): + assert isinstance(paramdata, dict) + for year, _ in paramdata.items(): + assert isinstance(year, int) + if year not in years: + years.append(year) + return years + # ----- begin private methods of Parameters class ----- - def _set_default_vals(self, wage_indexed_params=None, known_years=999999): + def _set_default_vals(self, known_years=999999): """ Called by initialize method and from some subclass methods. """ # pylint: disable=too-many-branches,too-many-nested-blocks - if wage_indexed_params is None: - wage_indexed_param_list = list() - else: - assert isinstance(wage_indexed_params, list) - wage_indexed_param_list = wage_indexed_params assert isinstance(known_years, (int, dict)) if isinstance(known_years, int): known_years_is_int = True @@ -146,7 +221,7 @@ def _set_default_vals(self, wage_indexed_params=None, known_years=999999): indexed = data.get('indexed', False) # pylint: disable=assignment-from-none if indexed: - if name in wage_indexed_param_list: + if name in self._wage_indexed: index_rates = self.wage_growth_rates() else: index_rates = self.inflation_rates() @@ -163,80 +238,106 @@ def _set_default_vals(self, wage_indexed_params=None, known_years=999999): num_years=self._num_years)) self.set_year(self._start_year) - def _update(self, year_mods, wage_indexed_params=None): + def _update(self, revision_, print_warnings, raise_errors): """ - Private method used by public implement_reform and update_* methods - in inheriting classes. + Update parameters using specified revision_ dictionary and + leave current_year unchanged. Parameters ---------- - year_mods: dictionary containing a single YEAR:MODS pair - see Notes below for details on dictionary structure. + revision_: parameter-changes dictionary in param:year:value format + + print_warnings: boolean + if True, prints warnings when parameter_warnings exists; + if False, does not print warnings when parameter_warnings exists + and leaves warning handling to caller of _update method. + + raise_errors: boolean + if True, raises ValueError when parameter_errors exists; + if False, does not raise ValueError when parameter_errors exists + and leaves error handling to caller of _update method. Raises ------ ValueError: - if year_mods is not a dictionary of the expected structure. + if revision_ is not a dictionary. + if each revision_ key is not a valid parameter name + if minimum YEAR in revision_ is less than current_year. + if maximum YEAR in revision_ is greater than end_year. + if _validate_names_types generates errors + if _validate_values generates errors and raise_errors is True Returns ------- nothing: void - - Notes - ----- - This is a private method that should **NEVER** be used by clients - of the inheriting classes. Instead, always use the public - implement_reform or update_consumption-like methods defined by - the inheriting class. This is a private method that helps the - public methods work. - - This method implements a policy reform or assumption modification, - the provisions of which are specified in the year_mods dictionary, - that changes the values of some parameters in objects of the - inheriting class. This year_mods dictionary contains exactly one - YEAR:MODS pair, where the integer YEAR key indicates the - calendar year for which the parameter revisions in the MODS - dictionary are implemented. The MODS dictionary contains - PARAM:VALUE pairs in which the PARAM is a string specifying - the parameter (as used in the DEFAULTS_FILE_NAME default - parameter file) and the VALUE is a Python list of post-update - values for that PARAM in that YEAR. Beginning in the year - following the implementation of a revision provision, the - parameter whose value has been changed by the revision continues - to be price or wage indexed, if relevant, or not be indexed - according to that parameter's indexed value loaded from the - DEFAULTS_FILE_NAME. For a indexable parameter, a reform can change - the indexing status of a parameter by including in the MODS dictionary - a term that is a PARAM_cpi:BOOLEAN pair specifying the post-reform - indexing status of the parameter. - - So, for example, to raise the OASDI (i.e., Old-Age, Survivors, - and Disability Insurance) maximum taxable earnings beginning - in 2018 to $500,000 and to continue indexing it in subsequent - years as in current-law policy, the YEAR:MODS dictionary would - be as follows:: - - {2018: {"_SS_Earnings_c":[500000]}} - - But to raise the maximum taxable earnings in 2018 to $500,000 - without any indexing in subsequent years, the YEAR:MODS - dictionary would be as follows:: - - {2018: {"_SS_Earnings_c":[500000], "_SS_Earnings_c_cpi":False}} - - And to raise in 2019 the starting AGI for EITC phaseout for - married filing jointly filing status (which is a two-dimensional - policy parameter that varies by the number of children from zero - to three or more and is inflation indexed), the YEAR:MODS dictionary - would be as follows:: - - {2019: {"_EITC_ps_MarriedJ":[[8000, 8500, 9000, 9500]]}} - - Notice the pair of double square brackets around the four values - for 2019. The one-dimensional parameters above require only a pair - of single square brackets. """ - # pylint: disable=too-many-statements,too-many-locals + # pylint: disable=too-many-locals,too-many-branches + # check revisions_ type and whether empty + if not isinstance(revision_, dict): + raise ValueError('ERROR: YYYY PARAM revision_ is not a dictionary') + if not revision_: + return # no revisions provided to update parameters + # convert revision_ to revision with year:param:value format + revision = dict() + for name, namedata in revision_.items(): + if not isinstance(name, str): + msg = 'ERROR: KEY {} is not a string parameter name' + raise ValueError(msg.format(name)) + if not isinstance(namedata, dict): + msg = 'ERROR: KEY {} VAL {} is not a year:value dictionary' + raise ValueError(msg.format(name, namedata)) + for year, yeardata in namedata.items(): + if not isinstance(year, int): + msg = 'ERROR: KEY {} YEAR {} is not an integer year' + raise ValueError(msg.format(name, year)) + if year not in revision: + revision[year] = dict() + revision[year][name] = yeardata + # check range of revision years + revision_years = list(revision.keys()) + first_revision_year = min(revision_years) + if first_revision_year < self.current_year: + msg = 'ERROR: {} YEAR revision provision in YEAR < current_year={}' + raise ValueError(msg.format(first_revision_year, + self.current_year)) + last_revision_year = max(revision_years) + if last_revision_year > self.end_year: + msg = 'ERROR: {} YEAR revision provision in YEAR > end_year={}' + raise ValueError(msg.format(last_revision_year, self.end_year)) + # add leading underscore character to each parameter name in revision + revision = Parameters._add_underscores(revision) + # add brackets around each value element in revision + revision = Parameters._add_brackets(revision) + # validate revision parameter names and types + self.parameter_warnings = '' + self.parameter_errors = '' + self._validate_names_types(revision) + if self.parameter_errors: + raise ValueError(self.parameter_errors) + # optionally apply CPI_offset to inflation_rates and re-initialize + known_years = self._apply_cpi_offset_in_revision(revision) + if known_years is not None: + self._set_default_vals(known_years=known_years) + # implement the revision year by year + precall_current_year = self.current_year + revision_parameters = set() + for year in sorted(revision_years): + self.set_year(year) + revision_parameters.update(revision[year].keys()) + self._update_for_year({year: revision[year]}) + self.set_year(precall_current_year) + # validate revision parameter values + self._validate_values(revision_parameters) + if self.parameter_warnings and print_warnings: + print(self.parameter_warnings) + if self.parameter_errors and raise_errors: + raise ValueError('\n' + self.parameter_errors) + + def _update_for_year(self, year_mods): + """ + Private method used by Parameters._update method. + """ + # pylint: disable=too-many-locals # check YEAR value in the single YEAR:MODS dictionary parameter assert isinstance(year_mods, dict) assert len(year_mods.keys()) == 1 @@ -244,33 +345,27 @@ def _update(self, year_mods, wage_indexed_params=None): assert year == self.current_year # check that MODS is a dictionary assert isinstance(year_mods[year], dict) - # specify wage_indexed_param_list - if wage_indexed_params is None: - wage_indexed_param_list = list() - else: - assert isinstance(wage_indexed_params, list) - wage_indexed_param_list = wage_indexed_params # implement reform provisions included in the single YEAR:MODS pair num_years_to_expand = (self.start_year + self.num_years) - year all_names = set(year_mods[year].keys()) # no duplicate keys in a dict used_names = set() # set of used parameter names in MODS dict for name, values in year_mods[year].items(): # determine indexing status of parameter with name for year - if name.endswith('_cpi'): + if name.endswith('-indexed'): continue # handle elsewhere in this method vals_indexed = self._vals[name].get('indexed', False) valtype = self._vals[name].get('value_type') - name_plus_cpi = name + '_cpi' - if name_plus_cpi in year_mods[year].keys(): - used_names.add(name_plus_cpi) - indexed = year_mods[year].get(name_plus_cpi) + name_plus_indexed = name + '-indexed' + if name_plus_indexed in year_mods[year].keys(): + used_names.add(name_plus_indexed) + indexed = year_mods[year].get(name_plus_indexed) self._vals[name]['indexed'] = indexed # remember status else: indexed = vals_indexed # set post-reform values of parameter with name used_names.add(name) cval = getattr(self, name, None) - wage_indexed_param = name in wage_indexed_param_list + wage_indexed_param = name in self._wage_indexed index_rates = self._indexing_rates_for_update(wage_indexed_param, year, num_years_to_expand) @@ -279,17 +374,17 @@ def _update(self, year_mods, wage_indexed_params=None): inflation_rates=index_rates, num_years=num_years_to_expand) cval[(year - self.start_year):] = nval - # handle unused parameter names, all of which end in _cpi, but some - # parameter names ending in _cpi were handled above + # handle unused parameter names, all of which end in -indexed, but + # some parameter names ending in -indexed were handled above unused_names = all_names - used_names for name in unused_names: used_names.add(name) - pname = name[:-4] # root parameter name + pname = name[:-8] # root parameter name pindexed = year_mods[year][name] self._vals[pname]['indexed'] = pindexed # remember status cval = getattr(self, pname, None) pvalues = [cval[year - self.start_year]] - wage_indexed_param = pname in wage_indexed_param_list + wage_indexed_param = pname in self._wage_indexed index_rates = self._indexing_rates_for_update(wage_indexed_param, year, num_years_to_expand) @@ -304,55 +399,53 @@ def _update(self, year_mods, wage_indexed_params=None): # implement updated parameters for year self.set_year(year) - def _validate_names_types(self, revision, removed_names=None): + def _validate_names_types(self, revision): """ Check validity of parameter names and parameter types used - in the specified revision dictionary. The optional - removed_names list contains parameter names that were once valid - but are no longer valid. + in the specified revision dictionary, which is assumed to + have a year:param:value format """ # pylint: disable=too-many-branches,too-many-nested-blocks # pylint: disable=too-many-statements,too-many-locals - if removed_names is None: - removed_param_names = set() - else: - assert isinstance(removed_names, list) - removed_param_names = set(removed_names) assert isinstance(self._vals, dict) param_names = set(self._vals.keys()) for year in sorted(revision.keys()): for name in revision[year]: - if name.endswith('_cpi'): + if name.endswith('-indexed'): if isinstance(revision[year][name], bool): - pname = name[:-4] # root parameter name + pname = name[:-8] # root parameter name if pname not in param_names: - if pname in removed_param_names: - msg = '{} {} is a removed parameter name' + if pname in self._removed: + msg = self._removed[pname] else: - msg = '{} {} is an unknown parameter name' + msg = 'is an unknown parameter name' self.parameter_errors += ( - 'ERROR: ' + msg.format(year, name) + '\n' + 'ERROR: {} {} '.format(year, name[1:]) + + msg + '\n' ) else: # check if root parameter is indexable - if not self._vals[pname]['indexable']: + indexable = self._vals[pname].get('indexable', + False) + if not indexable: msg = '{} {} parameter is not indexable' self.parameter_errors += ( - 'ERROR: ' + msg.format(year, pname) + '\n' + 'ERROR: ' + + msg.format(year, pname[1:]) + '\n' ) else: msg = '{} {} parameter is not true or false' self.parameter_errors += ( - 'ERROR: ' + msg.format(year, name) + '\n' + 'ERROR: ' + msg.format(year, name[1:]) + '\n' ) - else: # if name does not end with '_cpi' + else: # if name does not end with '-indexed' if name not in param_names: - if name in removed_param_names: - msg = '{} {} is a removed parameter name' + if name in self._removed: + msg = self._removed[name] else: - msg = '{} {} is an unknown parameter name' + msg = 'is an unknown parameter name' self.parameter_errors += ( - 'ERROR: ' + msg.format(year, name) + '\n' + 'ERROR: {} {} '.format(year, name[1:]) + msg + '\n' ) else: # check parameter value type avoiding use of isinstance @@ -363,15 +456,34 @@ def _validate_names_types(self, revision, removed_names=None): pvalue = revision[year][name][0] if isinstance(pvalue, list): scalar = False # parameter value is a list + if not self._vals[name].get('vi_vals', []): + msg = ('{} {} with value {} ' + 'should be a scalar parameter') + self.parameter_errors += ( + 'ERROR: ' + + msg.format(year, name[1:], pvalue) + + '\n' + ) + # following is not true but is needed to + # avoid errors below + scalar = True else: scalar = True # parameter value is a scalar + if self._vals[name].get('vi_vals', []): + msg = ('{} {} with value {} ' + 'should be a vector parameter') + self.parameter_errors += ( + 'ERROR: ' + + msg.format(year, name[1:], pvalue) + + '\n' + ) pvalue = [pvalue] # make scalar a single-item list # pylint: disable=consider-using-enumerate for idx in range(0, len(pvalue)): if scalar: pname = name else: - col = self._vals[name]['col_label'][idx] + col = self._vals[name]['vi_vals'][idx] pname = '{}[{}]'.format(name, col) pval = pvalue[idx] # pylint: disable=unidiomatic-typecheck @@ -380,7 +492,7 @@ def _validate_names_types(self, revision, removed_names=None): msg = '{} {} value {} is not a number' self.parameter_errors += ( 'ERROR: ' + - msg.format(year, pname, pval) + + msg.format(year, pname[1:], pval) + '\n' ) elif valtype == 'boolean': @@ -388,7 +500,7 @@ def _validate_names_types(self, revision, removed_names=None): msg = '{} {} value {} is not boolean' self.parameter_errors += ( 'ERROR: ' + - msg.format(year, pname, pval) + + msg.format(year, pname[1:], pval) + '\n' ) elif valtype == 'integer': @@ -396,7 +508,7 @@ def _validate_names_types(self, revision, removed_names=None): msg = '{} {} value {} is not integer' self.parameter_errors += ( 'ERROR: ' + - msg.format(year, pname, pval) + + msg.format(year, pname[1:], pval) + '\n' ) elif valtype == 'string': @@ -404,35 +516,26 @@ def _validate_names_types(self, revision, removed_names=None): msg = '{} {} value {} is not a string' self.parameter_errors += ( 'ERROR: ' + - msg.format(year, pname, pval) + + msg.format(year, pname[1:], pval) + '\n' ) del param_names - def _validate_values(self, parameters_set, redefined_info=None): + def _validate_values(self, parameters_set): """ Check values of parameters in specified parameter_set using - range information from DEFAULTS_FILE_NAME JSON file. The - optional redefined_info argument is a dictionary of parameter - name:message pairs for parameters whose meaning has been changed - recently and for whom warning messages are to be issued. + range information from DEFAULTS_FILE_NAME JSON file. """ # pylint: disable=too-many-statements,too-many-locals # pylint: disable=too-many-branches,too-many-nested-blocks assert isinstance(parameters_set, set) parameters = sorted(parameters_set) - if redefined_info is None: - redefined_pinfo = dict() - else: - redefined_pinfo = redefined_info - assert isinstance(redefined_pinfo, dict) - redefined_pnames = redefined_pinfo.keys() syr = self.start_year for pname in parameters: - if pname.endswith('_cpi'): - continue # *_cpi parameter values validated elsewhere - if pname in redefined_pnames: - msg = redefined_pinfo[pname] + if pname.endswith('-indexed'): + continue # *-indexed parameter values validated elsewhere + if pname in self._redefined: + msg = self._redefined[pname] self.parameter_warnings += msg + '\n' pvalue = getattr(self, pname) if self._vals[pname]['value_type'] == 'string': @@ -443,7 +546,7 @@ def _validate_values(self, parameters_set, redefined_info=None): fullmsg = '{}: {}\n'.format( 'ERROR', msg.format(idx[0] + syr, - pname, + pname[1:], pvalue[idx], valid_options) ) @@ -451,7 +554,7 @@ def _validate_values(self, parameters_set, redefined_info=None): else: # parameter does not have string type for vop, vval in self._vals[pname]['valid_values'].items(): if isinstance(vval, str): - vvalue = getattr(self, vval) + vvalue = getattr(self, '_' + vval) else: vvalue = np.full(pvalue.shape, vval) assert pvalue.shape == vvalue.shape @@ -465,21 +568,22 @@ def _validate_values(self, parameters_set, redefined_info=None): if vop == 'min' and pvalue[idx] < vvalue[idx]: out_of_range = True msg = '{} {} value {} < min value {}' - extra = self._vals[pname]['invalid_minmsg'] + extra = self._vals[pname].get('invalid_minmsg', '') if extra: msg += ' {}'.format(extra) if vop == 'max' and pvalue[idx] > vvalue[idx]: out_of_range = True msg = '{} {} value {} > max value {}' - extra = self._vals[pname]['invalid_maxmsg'] + extra = self._vals[pname].get('invalid_maxmsg', '') if extra: msg += ' {}'.format(extra) if out_of_range: - action = self._vals[pname]['invalid_action'] + action = self._vals[pname].get('invalid_action', + 'stop') if scalar: name = pname else: - col = self._vals[pname]['col_label'][idx[1]] + col = self._vals[pname]['vi_vals'][idx[1]] name = '{}[{}]'.format(pname, col) if extra: msg += '[{}]'.format(col) @@ -496,7 +600,7 @@ def _validate_values(self, parameters_set, redefined_info=None): fullmsg = '{}: {}\n'.format( 'ERROR', msg.format(idx[0] + syr, - name, + name[1:], pvalue[idx], vvalue[idx]) ) @@ -631,3 +735,109 @@ def _indexing_rates_for_update(self, param_is_wage_indexed, for i in range(0, num_years_to_expand)] return expanded_rates return None + + @staticmethod + def _add_underscores(update_dict): + """ + Returns dictionary that adds leading underscore character to + each parameter name in specified update_dict, which is assumed + to have a year:param:value format. + """ + updict = dict() + for year, yeardata in update_dict.items(): + updict[year] = dict() + for pname, pvalue in yeardata.items(): + updict[year]['_' + pname] = pvalue + return updict + + @staticmethod + def _add_brackets(update_dict): + """ + Returns dictionary that adds brackets around each + data element (value) in specified update_dict, which + is assumed to have a year:param:value format. + """ + updict = dict() + for year, yeardata in update_dict.items(): + updict[year] = dict() + for pname, pvalue in yeardata.items(): + if pname.endswith('-indexed'): + updict[year][pname] = pvalue # no added brackets + else: + updict[year][pname] = [pvalue] + return updict + + def _apply_cpi_offset_to_inflation_rates(self): + """ + Called from Parameters.initialize method. + Does nothing if CPI_offset parameter is not in self._vals dictionary. + """ + if '_CPI_offset' not in self._vals: + return + nyrs = self.num_years + ovalues = self._vals['_CPI_offset']['value'] + if len(ovalues) < nyrs: # extrapolate last known value + ovalues = ovalues + ovalues[-1:] * (nyrs - len(ovalues)) + for idx in range(0, nyrs): + infrate = round(self._inflation_rates[idx] + ovalues[idx], 6) + self._inflation_rates[idx] = infrate + + def _apply_cpi_offset_in_revision(self, revision): + """ + Apply CPI offset to inflation rates and + revert indexed parameter values in preparation for re-indexing. + Also, return known_years which is dictionary with indexed policy + parameter names as keys and known_years as values. For indexed + parameters included in revision, the known_years value is equal to: + (first_cpi_offset_year - start_year + 1). For indexed parameters + not included in revision, the known_years value is equal to: + (max(first_cpi_offset_year, last_known_year) - start_year + 1). + """ + # pylint: disable=too-many-branches + # determine if CPI_offset is in specified revision; if not, return + cpi_offset_in_revision = False + for year in revision: + for name in revision[year]: + if name == '_CPI_offset': + cpi_offset_in_revision = True + break # out of loop + if not cpi_offset_in_revision: + return None + # extrapolate CPI_offset revision + self.set_year(self.start_year) + first_cpi_offset_year = 0 + for year in sorted(revision.keys()): + self.set_year(year) + if '_CPI_offset' in revision[year]: + if first_cpi_offset_year == 0: + first_cpi_offset_year = year + orevision = {'_CPI_offset': revision[year]['_CPI_offset']} + self._update_for_year({year: orevision}) + self.set_year(self.start_year) + assert first_cpi_offset_year > 0 + # adjust inflation rates + cpi_offset = getattr(self, '_CPI_offset') + for idx in range(0, self.num_years): + infrate = round(self._inflation_rates[idx] + cpi_offset[idx], 6) + self._inflation_rates[idx] = infrate + # revert indexed parameter values to policy_current_law.json values + for name in self._vals.keys(): + if self._vals[name]['indexed']: + setattr(self, name, self._vals[name]['value']) + # construct and return known_years dictionary + known_years = dict() + kyrs_in_revision = (first_cpi_offset_year - self.start_year + 1) + kyrs_not_in_revision = ( + max(first_cpi_offset_year, self.last_known_year) - + self.start_year + 1 + ) + for year in sorted(revision.keys()): + for name in revision[year]: + if self._vals[name]['indexed']: + if name not in known_years: + known_years[name] = kyrs_in_revision + for name in self._vals.keys(): + if self._vals[name]['indexed']: + if name not in known_years: + known_years[name] = kyrs_not_in_revision + return known_years diff --git a/taxcalc/policy.py b/taxcalc/policy.py index aa1c2258d..4edf94f66 100644 --- a/taxcalc/policy.py +++ b/taxcalc/policy.py @@ -6,8 +6,6 @@ # pylint --disable=locally-disabled policy.py import os -import collections -import numpy as np from taxcalc.parameters import Parameters from taxcalc.growfactors import GrowFactors @@ -43,25 +41,28 @@ class instance: Policy # should increase LAST_BUDGET_YEAR by one every calendar year DEFAULT_NUM_YEARS = LAST_BUDGET_YEAR - JSON_START_YEAR + 1 - # specify which Policy parameters are wage (rather than price) indexed + # NOTE: the following three data structures use internal parameter names: + # (1) specify which Policy parameters have been removed or renamed + REMOVED_PARAMS = { + # following five parameters removed in PR 2223 merged on 2019-02-06 + '_DependentCredit_Child_c': 'is a removed parameter name', + '_DependentCredit_Nonchild_c': 'is a removed parameter name', + '_DependentCredit_before_CTC': 'is a removed parameter name', + '_FilerCredit_c': 'is a removed parameter name', + '_ALD_InvInc_ec_base_RyanBrady': 'is a removed parameter name', + # TODO: following parameter renamed in PR 2292 merged on 2019-04-?? + '_cpi_offset': 'was renamed CPI_offset in release 2.0.0' + } + # (2) specify which Policy parameters have been redefined recently + REDEFINED_PARAMS = { + # TODO: remove the CTC_c name:message pair sometime later in 2019 + '_CTC_c': 'CTC_c was redefined in release 1.0.0' + } + # (3) specify which Policy parameters are wage (rather than price) indexed WAGE_INDEXED_PARAMS = [ '_SS_Earnings_c', '_SS_Earnings_thd' ] - # specify which Policy parameters have been removed - REMOVED_PARAMS = [ - # following five parameters removed in PR 2223 merged on 2019-02-06 - '_DependentCredit_Child_c', - '_DependentCredit_Nonchild_c', - '_DependentCredit_before_CTC', - '_FilerCredit_c', - '_ALD_InvInc_ec_base_RyanBrady' - ] - # specify which Policy parameters havve been redefined recently - REDEFINED_PARAMS = { - # TODO: remove the _CTC_c name:message pair sometime later in 2019 - '_CTC_c': '_CTC_c was redefined in release 1.0.0 (2019-02-22)' - } def __init__(self, gfactors=None, only_reading_defaults=False): # put JSON contents of DEFAULTS_FILE_NAME into self._vals dictionary @@ -80,12 +81,11 @@ def __init__(self, gfactors=None, only_reading_defaults=False): lyr = Policy.LAST_BUDGET_YEAR nyrs = Policy.DEFAULT_NUM_YEARS self._inflation_rates = self._gfactors.price_inflation_rates(syr, lyr) - self._apply_clp_cpi_offset(self._vals['_cpi_offset'], nyrs) self._wage_growth_rates = self._gfactors.wage_growth_rates(syr, lyr) - self.initialize(syr, nyrs, Policy.WAGE_INDEXED_PARAMS) - # initialize parameter warning/error variables - self.parameter_warnings = '' - self.parameter_errors = '' + self.initialize(syr, nyrs, Policy.LAST_KNOWN_YEAR, + Policy.REMOVED_PARAMS, + Policy.REDEFINED_PARAMS, + Policy.WAGE_INDEXED_PARAMS) def inflation_rates(self): """ @@ -102,159 +102,10 @@ def wage_growth_rates(self): def implement_reform(self, reform, print_warnings=True, raise_errors=True): """ - Implement multi-year policy reform and leave current_year unchanged. - - Parameters - ---------- - reform: dictionary of one or more YEAR:MODS pairs - see Notes to Parameters _update method for info on MODS structure - - print_warnings: boolean - if True, prints warnings when parameter_warnings exists; - if False, does not print warnings when parameter_warnings exists - and leaves warning handling to caller of implement_reform. - - raise_errors: boolean - if True, raises ValueError when parameter_errors exists; - if False, does not raise ValueError when parameter_errors exists - and leaves error handling to caller of implement_reform. - - Raises - ------ - ValueError: - if reform is not a dictionary. - if each YEAR in reform is not an integer. - if minimum YEAR in the YEAR:MODS pairs is less than start_year. - if minimum YEAR in the YEAR:MODS pairs is less than current_year. - if maximum YEAR in the YEAR:MODS pairs is greater than end_year. - if raise_errors is True AND - _validate_names_types generates errors OR - _validate_values generates errors. - - Returns - ------- - nothing: void - - Notes - ----- - Given a reform dictionary, typical usage of the Policy class - is as follows:: - - policy = Policy() - policy.implement_reform(reform) - - In the above statements, the Policy() call instantiates a - policy object (policy) containing current-law policy parameters, - and the implement_reform(reform) call applies the (possibly - multi-year) reform specified in reform and then sets the - current_year to the value of current_year when implement_reform - was called with parameters set for that pre-call year. - - An example of a multi-year, multi-parameter reform is as follows:: - - reform = { - 2016: { - '_EITC_c': [[900, 5000, 8000, 9000]], - '_II_em': [7000], - '_SS_Earnings_c': [300000] - }, - 2017: { - '_SS_Earnings_c': [500000], '_SS_Earnings_c_cpi': False - }, - 2019: { - '_EITC_c': [[1200, 7000, 10000, 12000]], - '_II_em': [9000], - '_SS_Earnings_c': [700000], '_SS_Earnings_c_cpi': True - } - } - - Notice that each of the four YEAR:MODS pairs is specified as - required by the private _update method, whose documentation - provides several MODS dictionary examples. - - IMPORTANT NOTICE: when specifying a reform dictionary always group - all reform provisions for a specified year into one YEAR:MODS pair. - If you make the mistake of specifying two or more YEAR:MODS pairs - with the same YEAR value, all but the last one will be overwritten, - and therefore, not part of the reform. This is because Python - expects unique (not multiple) dictionary keys. There is no way to - catch this error, so be careful to specify reform dictionaries - correctly. - """ - # pylint: disable=too-many-locals - # check that all reform dictionary keys are integers - if not isinstance(reform, dict): - raise ValueError('ERROR: YYYY PARAM reform is not a dictionary') - if not reform: - return # no reform to implement - reform_years = sorted(list(reform.keys())) - for year in reform_years: - if not isinstance(year, int): - msg = 'ERROR: {} KEY {}' - details = 'KEY in reform is not an integer calendar year' - raise ValueError(msg.format(year, details)) - # check range of remaining reform_years - first_reform_year = min(reform_years) - if first_reform_year < self.start_year: - msg = 'ERROR: {} YEAR reform provision in YEAR < start_year={}' - raise ValueError(msg.format(first_reform_year, self.start_year)) - if first_reform_year < self.current_year: - msg = 'ERROR: {} YEAR reform provision in YEAR < current_year={}' - raise ValueError(msg.format(first_reform_year, self.current_year)) - last_reform_year = max(reform_years) - if last_reform_year > self.end_year: - msg = 'ERROR: {} YEAR reform provision in YEAR > end_year={}' - raise ValueError(msg.format(last_reform_year, self.end_year)) - # validate reform parameter names and types - self.parameter_warnings = '' - self.parameter_errors = '' - self._validate_names_types(reform, - removed_names=Policy.REMOVED_PARAMS) - if self.parameter_errors: - raise ValueError(self.parameter_errors) - # optionally apply cpi_offset to inflation_rates and re-initialize - if Policy._cpi_offset_in_reform(reform): - known_years = self._apply_reform_cpi_offset(reform) - self._set_default_vals( - wage_indexed_params=Policy.WAGE_INDEXED_PARAMS, - known_years=known_years - ) - # implement the reform year by year - precall_current_year = self.current_year - reform_parameters = set() - for year in reform_years: - self.set_year(year) - reform_parameters.update(reform[year].keys()) - self._update({year: reform[year]}, Policy.WAGE_INDEXED_PARAMS) - self.set_year(precall_current_year) - # validate reform parameter values - self._validate_values(reform_parameters, - redefined_info=Policy.REDEFINED_PARAMS) - if self.parameter_warnings and print_warnings: - print(self.parameter_warnings) - if self.parameter_errors and raise_errors: - raise ValueError('\n' + self.parameter_errors) - - def metadata(self): + Implement specified policy reform and leave current_year unchanged. + (see Parameters._update for argument documentation.) """ - Returns ordered dictionary of parameter information based on - the contents of the policy_current_law.json file with updates - to each parameter's 'start_year', 'row_label', and 'value' key - values so that the updated values contain just the current_year - information for this instance of the Policy class. - """ - mdata = collections.OrderedDict() - for pname, pdata in self._vals.items(): - mdata[pname] = pdata - mdata[pname]['row_label'] = ['{}'.format(self.current_year)] - mdata[pname]['start_year'] = '{}'.format(self.current_year) - valraw = getattr(self, pname[1:]) - if isinstance(valraw, np.ndarray): - val = valraw.tolist() - else: - val = valraw - mdata[pname]['value'] = [val] - return mdata + self._update(reform, print_warnings, raise_errors) @staticmethod def parameter_list(): @@ -265,82 +116,3 @@ def parameter_list(): plist = list(policy._vals.keys()) # pylint: disable=protected-access del policy return plist - - # ----- begin private methods of Policy class ----- - - def _apply_clp_cpi_offset(self, cpi_offset_clp_data, num_years): - """ - Call this method from Policy constructor - after self._inflation_rates has been set and - before base class initialize method is called. - (num_years is number of years for which inflation rates are specified) - """ - ovalues = cpi_offset_clp_data['value'] - if len(ovalues) < num_years: # extrapolate last known value - ovalues = ovalues + ovalues[-1:] * (num_years - len(ovalues)) - for idx in range(0, num_years): - infrate = round(self._inflation_rates[idx] + ovalues[idx], 6) - self._inflation_rates[idx] = infrate - - @staticmethod - def _cpi_offset_in_reform(reform): - """ - Return true if cpi_offset is in reform; otherwise return false. - """ - for year in reform: - for name in reform[year]: - if name == '_cpi_offset': - return True - return False - - def _apply_reform_cpi_offset(self, reform): - """ - Call this method ONLY if _cpi_offset_in_reform returns True. - Apply CPI offset to inflation rates and - revert indexed parameter values in preparation for re-indexing. - Also, return known_years which is dictionary with indexed policy - parameter names as keys and known_years as values. For indexed - parameters included in reform, the known_years value is equal to: - (first_cpi_offset_year - start_year + 1). For indexed parameters - not included in reform, the known_years value is equal to: - (max(first_cpi_offset_year, Policy.LAST_KNOWN_YEAR) - start_year + 1). - """ - # pylint: disable=too-many-branches - # extrapolate cpi_offset reform - self.set_year(self.start_year) - first_cpi_offset_year = 0 - for year in sorted(reform.keys()): - self.set_year(year) - if '_cpi_offset' in reform[year]: - if first_cpi_offset_year == 0: - first_cpi_offset_year = year - oreform = {'_cpi_offset': reform[year]['_cpi_offset']} - self._update({year: oreform}, Policy.WAGE_INDEXED_PARAMS) - self.set_year(self.start_year) - assert first_cpi_offset_year > 0 - # adjust inflation rates - cpi_offset = getattr(self, '_cpi_offset') - for idx in range(0, self.num_years): - infrate = round(self._inflation_rates[idx] + cpi_offset[idx], 6) - self._inflation_rates[idx] = infrate - # revert indexed parameter values to policy_current_law.json values - for name in self._vals.keys(): - if self._vals[name]['indexed']: - setattr(self, name, self._vals[name]['value']) - # construct and return known_years dictionary - known_years = dict() - kyrs_in_reform = (first_cpi_offset_year - - self.start_year + 1) - kyrs_not_in_reform = (max(first_cpi_offset_year, - Policy.LAST_KNOWN_YEAR) - - self.start_year + 1) - for year in sorted(reform.keys()): - for name in reform[year]: - if self._vals[name]['indexed']: - if name not in known_years: - known_years[name] = kyrs_in_reform - for name in self._vals.keys(): - if self._vals[name]['indexed']: - if name not in known_years: - known_years[name] = kyrs_not_in_reform - return known_years diff --git a/taxcalc/policy_current_law.json b/taxcalc/policy_current_law.json index 2fb9a6576..cf39b8e05 100644 --- a/taxcalc/policy_current_law.json +++ b/taxcalc/policy_current_law.json @@ -1,20 +1,20 @@ { - "_cpi_offset": { + "CPI_offset": { "long_name": "Decimal offset ADDED to unchained CPI to get parameter indexing rate", - "description": "Current-law values are zero; reforms that introduce indexing with chained CPI would have values around -0.0025 beginning in the year before the first year policy parameters will have values computed with chained CPI.", + "description": "Values are zero before 2017; reforms that introduce indexing with chained CPI would have values around -0.0025 beginning in the year before the first year policy parameters will have values computed with chained CPI.", "section_1": "Parameter Indexing", "section_2": "Offsets", "irs_ref": "", "notes": "See April 2013 CBO report entitled 'What Would Be the Effect on the Deficit of Using the Chained CPI to Index Benefit Programs and the Tax Code?', which includes this: 'The chained CPI grows more slowly than the traditional CPI does: an average of about 0.25 percentage points more slowly per year over the past decade.' ", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -28,18 +28,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_FICA_ss_trt": { + "FICA_ss_trt": { "long_name": "Social Security payroll tax rate", "description": "Social Security FICA rate, including both employer and employee.", "section_1": "Payroll Taxes", "section_2": "Social Security FICA", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.124], "valid_values": {"min": 0, "max": 1}, @@ -49,23 +49,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_SS_Earnings_c": { + "SS_Earnings_c": { "long_name": "Maximum taxable earnings (MTE) for Social Security", "description": "Individual earnings below this amount are subjected to Social Security (OASDI) payroll tax.", "section_1": "Payroll Taxes", "section_2": "Social Security FICA", "irs_ref": "W-2, Box 4, instructions", "notes": "This parameter is indexed by the rate of growth in average wages, not by the price inflation rate.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [113700.0, 117000.0, @@ -80,18 +80,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_SS_Earnings_thd": { + "SS_Earnings_thd": { "long_name": "Additional Taxable Earnings Threshold for Social Security", "description": "Individual earnings above this threshold are subjected to Social Security (OASDI) payroll tax, in addition to earnings below the maximum taxable earnings threshold.", "section_1": "Payroll Taxes", "section_2": "Social Security FICA", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [9e99], "valid_values": {"min": 0, "max": 9e99}, @@ -101,18 +101,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_FICA_mc_trt": { + "FICA_mc_trt": { "long_name": "Medicare payroll tax rate", "description": "Medicare FICA rate, including both employer and employee.", "section_1": "Payroll Taxes", "section_2": "Medicare FICA", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.029], "valid_values": {"min": 0, "max": 1}, @@ -122,18 +122,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMEDT_ec": { + "AMEDT_ec": { "long_name": "Additional Medicare tax earnings exclusion", "description": "The Additional Medicare Tax rate, _AMEDT_rt, applies to all earnings in excess of this excluded amount.", "section_1": "Payroll Taxes", "section_2": "Additional Medicare FICA", "irs_ref": "Form 8959, line 5, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[200000.0, 250000.0, 125000.0, 200000.0, 200000.0]], "valid_values": {"min": 0, "max": 9e99}, @@ -143,18 +143,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMEDT_rt": { + "AMEDT_rt": { "long_name": "Additional Medicare tax rate", "description": "This is the rate applied to the portion of Medicare wages, RRTA compensation and self-employment income exceeding the Additional Medicare Tax earning exclusion.", "section_1": "Payroll Taxes", "section_2": "Additional Medicare FICA", "irs_ref": "Form 8959, line 7, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.009], "valid_values": {"min": 0, "max": 1}, @@ -164,39 +164,39 @@ "compatible_data": {"puf": true, "cps": true} }, - "_SS_thd50": { + "SS_thd50": { "long_name": "Threshold for Social Security benefit taxability 1", "description": "The first threshold for Social Security benefit taxability: if taxpayers have provisional income greater than this threshold, up to 50% of their Social Security benefit will be subject to tax under current law.", "section_1": "Social Security Taxability", "section_2": "Threshold For Social Security Benefit Taxability 1", "irs_ref": "Form 1040, line 5a&b, calculation (Worksheet, line 8)", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[25000.0, 32000.0, 25000.0, 25000.0, 25000.0]], - "valid_values": {"min": 0, "max": "_SS_thd85"}, + "valid_values": {"min": 0, "max": "SS_thd85"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _SS_thd85", + "invalid_maxmsg": "for SS_thd85", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_SS_percentage1": { + "SS_percentage1": { "long_name": "Social Security taxable income decimal fraction 1", "description": "Under current law if their provisional income is above the first threshold for Social Security taxability but below the second threshold, taxpayers need to apply this fraction to both the excess of their provisional income over the first threshold and their Social Security benefits, and then include the smaller one in their AGI.", "section_1": "", "section_2": "", "irs_ref": "Form 1040, line 5b, instructions (Social Security Worksheets, line 2 & 13)", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.5], "valid_values": {"min": 0, "max": 1}, @@ -206,39 +206,39 @@ "compatible_data": {"puf": true, "cps": true} }, - "_SS_thd85": { + "SS_thd85": { "long_name": "Threshold for Social Security benefit taxability 2", "description": "The second threshold for Social Security taxability: if taxpayers have provisional income greater than this threshold, up to 85% of their Social Security benefit will be subject to tax under current law.", "section_1": "Social Security Taxability", "section_2": "Threshold For Social Security Benefit Taxability 2", "irs_ref": "Form 1040, line 5a&b, calculation (Worksheet, add line 10 values to line 8).", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[34000.0, 44000.0, 34000.0, 34000.0, 34000.0]], - "valid_values": {"min": "_SS_thd50", "max": 9e99}, - "invalid_minmsg": "for _SS_thd50", + "valid_values": {"min": "SS_thd50", "max": 9e99}, + "invalid_minmsg": "for SS_thd50", "invalid_maxmsg": "", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_SS_percentage2": { + "SS_percentage2": { "long_name": "Social Security taxable income decimal fraction 2", "description": "Under current law if their provisional income is above the second threshold for Social Security taxability, taxpayers need to apply this fraction to both the excess of their provisional income over the second threshold and their social security benefits, and then include the smaller one in their AGI.", "section_1": "", "section_2": "", "irs_ref": "Form 1040, line 5b, instructions (Social Security Worksheets, line 15)", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.85], "valid_values": {"min": 0, "max": 1}, @@ -248,18 +248,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_StudentLoan_hc": { + "ALD_StudentLoan_hc": { "long_name": "Adjustment for student loan interest haircut", "description": "This decimal fraction can be applied to limit the student loan interest adjustment allowed.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 1), line 33", "notes": "The final adjustment amount will be (1-Haircut)*StudentLoanInterest.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -269,18 +269,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_SelfEmploymentTax_hc": { + "ALD_SelfEmploymentTax_hc": { "long_name": "Adjustment for self-employment tax haircut", "description": "This decimal fraction, if greater than zero, reduces the employer equivalent portion of self-employment adjustment.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 4), line 57", "notes": "The final adjustment amount would be (1-Haircut)*SelfEmploymentTaxAdjustment.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -290,18 +290,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_SelfEmp_HealthIns_hc": { + "ALD_SelfEmp_HealthIns_hc": { "long_name": "Adjustment for self employed health insurance haircut", "description": "This decimal fraction, if greater than zero, reduces the health insurance adjustment for self-employed taxpayers.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 4), line 61", "notes": "The final adjustment amount would be (1-Haircut)*SelfEmployedHealthInsuranceAdjustment.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -311,18 +311,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_KEOGH_SEP_hc": { + "ALD_KEOGH_SEP_hc": { "long_name": "Adjustment for contributions to either KEOGH or SEP plan haircut", "description": "Under current law, contributions to Keogh or SEP plans can be fully deducted from gross income. This haircut can be used to limit the adjustment allowed.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 1), line 28", "notes": "The final adjustment amount is (1-Haircut)*KEOGH_SEP_Contributinos.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -332,18 +332,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_EarlyWithdraw_hc": { + "ALD_EarlyWithdraw_hc": { "long_name": "Adjustment for early withdrawal penalty haircut", "description": "Under current law, early withdraw penalty can be fully deducted from gross income. This haircut can be used to limit the adjustment allowed.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 1), line 30", "notes": "The final adjustment amount is (1-Haircut)*EarlyWithdrawPenalty.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -353,31 +353,31 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ALD_AlimonyPaid_hc": { + "ALD_AlimonyPaid_hc": { "long_name": "Adjustment for alimony-paid haircut", "description": "Under pre-TCJA law, the full amount of alimony paid is taken as an adjustment from gross income in arriving at AGI. This haircut can be used to change the deduction allowed.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 1), line 31", "notes": "The final adjustment amount would be (1-Haircut)*AlimonyPaid.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -400,31 +400,31 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ALD_AlimonyReceived_hc": { + "ALD_AlimonyReceived_hc": { "long_name": "Adjustment for alimony-received haircut", "description": "Under pre-TCJA law, none of alimony received is taken as an adjustment from gross income in arriving at AGI. This haircut can be used to change the deduction allowed.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "Form 1040 (Schedule 1), line 11 (new with TCJA)", "notes": "The final adjustment amount would be (1-Haircut)*AlimonyReceived.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0, 1.0, @@ -447,18 +447,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_EducatorExpenses_hc": { + "ALD_EducatorExpenses_hc": { "long_name": "Deduction for educator expenses haircut", "description": "If greater than zero, this decimal fraction reduces the portion of educator expenses that can be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "", "notes": "The final adjustment amount would be (1-Haircut)*EducatorExpenses.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -468,18 +468,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ALD_HSADeduction_hc": { + "ALD_HSADeduction_hc": { "long_name": "Deduction for HSA deduction haircut", "description": "If greater than zero, this decimal fraction reduces the portion of a taxpayer's HSA deduction that can be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "", "notes": "The final adjustment amount would be (1-Haircut)*HSA_Deduction.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -489,18 +489,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ALD_IRAContributions_hc": { + "ALD_IRAContributions_hc": { "long_name": "Deduction for IRA contributions haircut", "description": "If greater than zero, this decimal fraction reduces the portion of IRA contributions that can be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "", "notes": "The final adjustment amount would be (1-Haircut)*IRA_Contribution.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -510,31 +510,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_DomesticProduction_hc": { + "ALD_DomesticProduction_hc": { "long_name": "Deduction for domestic production activity haircut", "description": "If greater than zero, this decimal fraction reduces the portion of domestic production activity that can be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "", "notes": "The final adjustment amount would be (1-Haircut)*DomesticProductionActivity.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -557,18 +557,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_Tuition_hc": { + "ALD_Tuition_hc": { "long_name": "Deduction for tuition and fees haircut", "description": "If greater than zero, this decimal fraction reduces the portion of tuition and fees that can be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Adjustment Haircuts", "irs_ref": "", "notes": "The final adjustment amount would be (1-Haircut)*TuitionFees.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -578,18 +578,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ALD_InvInc_ec_rt": { + "ALD_InvInc_ec_rt": { "long_name": "Investment income exclusion rate haircut", "description": "Decimal fraction of investment income base that can be excluded from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Exclusions", "irs_ref": "Form 1040, line 2a", "notes": "The final taxable investment income will be (1-_ALD_InvInc_ec_rt)*investment_income_base. Even though the excluded portion of investment income is not included in AGI, it still is included in investment income used to calculate the Net Investment Income Tax and Earned Income Tax Credit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -599,18 +599,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_Dependents_hc": { + "ALD_Dependents_hc": { "long_name": "Deduction for childcare costs haircut", "description": "This decimal fraction, if greater than zero, reduces the portion of childcare costs that can be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Child And Elderly Care", "irs_ref": "", "notes": "The final adjustment would be (1-Haircut)*AverageChildcareCosts.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -620,23 +620,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_Dependents_Child_c": { + "ALD_Dependents_Child_c": { "long_name": "National average childcare costs: ceiling for available childcare deduction.", "description": "The weighted average of childcare costs in the US. 7165 is the weighted average from the 'Child Care in America: 2016 State Fact Sheets'.", "section_1": "Above The Line Deductions", "section_2": "Child And Elderly Care", "irs_ref": "", "notes": "This is a weighted average of childcare costs in each state", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -651,23 +651,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_Dependents_Elder_c": { + "ALD_Dependents_Elder_c": { "long_name": "Ceiling for elderly care deduction proposed in Trump's tax plan", "description": "A taxpayer can take an above the line deduction up to this amount if they have an elderly dependent. The Trump 2016 campaign proposal was for $5000.", "section_1": "Above The Line Deductions", "section_2": "Child And Elderly Care", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -682,18 +682,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_Dependents_thd": { + "ALD_Dependents_thd": { "long_name": "Maximum level of income to qualify for the dependent care deduction", - "description": "A taxpayer can only claim the dependent care deduction if their total income is below this level. The Trump 2016 campaign proposal was for 250000 single, 500000 joint, 250000 separate, 500000 headhousehold].", + "description": "A taxpayer can only claim the dependent care deduction if their total income is below this level. The Trump 2016 campaign proposal was for 250000 single, 500000 joint, 250000 separate, 500000 head of household].", "section_1": "Above The Line Deductions", "section_2": "Child And Elderly Care", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0]], "valid_values": {"min": 0, "max": 9e99}, @@ -703,31 +703,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ALD_BusinessLosses_c": { + "ALD_BusinessLosses_c": { "long_name": "Maximum amount of business losses deductible", "description": "Business losses in excess of this amount may not be deducted from AGI.", "section_1": "Above The Line Deductions", "section_2": "Misc. Exclusions", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -750,31 +750,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_em": { + "II_em": { "long_name": "Personal and dependent exemption amount", "description": "Subtracted from AGI in the calculation of taxable income, per taxpayer and dependent.", "section_1": "Personal Exemptions", "section_2": "Personal And Dependent Exemption Amount", "irs_ref": "Form 1040, line 42. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [3900.00, 3950.00, @@ -797,23 +797,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_em_ps": { + "II_em_ps": { "long_name": "Personal exemption phaseout starting income", "description": "If taxpayers' AGI is above this level, their personal exemption will start to decrease at the personal exemption phaseout rate (PEP provision).", "section_1": "", "section_2": "", "irs_ref": "Form 1040, line 42, instruction (Worksheet).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[250000.0, 300000.0, 150000.0, 275000.0, 300000.0], [254200.0, 305050.0, 152525.0, 279650.0, 305050.0], @@ -828,18 +828,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_prt": { + "II_prt": { "long_name": "Personal exemption phaseout rate", "description": "Personal exemption amount will decrease by this rate for each dollar of AGI exceeding exemption phaseout start.", "section_1": "Personal Exemptions", "section_2": "Personal Exemption Phaseout Rate", "irs_ref": "Form 1040, line 42, instruction (Worksheet).", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.02], "valid_values": {"min": 0, "max": 1}, @@ -849,18 +849,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_no_em_nu18": { + "II_no_em_nu18": { "long_name": "Repeal personal exemptions for dependents under age 18", "description": "Total personal exemptions will be decreased by the number of dependents under the age of 18.", "section_1": "Personal Exemptions", "section_2": "Repeal for Dependents Under Age 18", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -870,31 +870,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_STD": { + "STD": { "long_name": "Standard deduction amount", "description": "Amount filing unit can use as a standard deduction.", "section_1": "Standard Deduction", "section_2": "Standard Deduction Amount", "irs_ref": "Form 1040, line 8, instructions. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[6100.00, 12200.00, 6100.00, 8950.00, 12200.00], [6200.00, 12400.00, 6200.00, 9100.00, 12400.00], @@ -917,23 +917,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_STD_Dep": { + "STD_Dep": { "long_name": "Standard deduction for dependents", "description": "This is the maximum standard deduction for dependents.", "section_1": "", "section_2": "", "irs_ref": "Form 1040, line 8, instructions. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1000.0, 1000.0, @@ -948,23 +948,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_STD_Aged": { + "STD_Aged": { "long_name": "Additional standard deduction for blind and aged", "description": "To get the standard deduction for aged or blind individuals, taxpayers need to add this value to regular standard deduction.", "section_1": "Standard Deduction", "section_2": "Additional Standard Deduction For Blind And Aged", "irs_ref": "Form 1040, line 8, calculation (the difference of the two tables given in the instruction).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[1500.0, 1200.0, 1200.0, 1500.0, 1500.0], [1550.0, 1200.0, 1200.0, 1550.0, 1550.0], @@ -979,18 +979,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_STD_allow_charity_ded_nonitemizers": { + "STD_allow_charity_ded_nonitemizers": { "long_name": "Allow standard deduction filers to take the charitable contributions deduction", "description": "Extends the charitable contributions deduction to taxpayers who take the standard deduction. The same ceilings, floor, and haircuts applied to itemized deduction for charitable contributions also apply here.", "section_1": "", "section_2": "", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -1000,23 +1000,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_credit": { + "II_credit": { "long_name": "Personal refundable credit maximum amount", "description": "This credit amount is fully refundable and is phased out based on AGI. It is available to tax units who would otherwise not file.", "section_1": "Refundable Credits", "section_2": "Personal Refundable Credit", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -1031,23 +1031,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_credit_ps": { + "II_credit_ps": { "long_name": "Personal refundable credit phaseout start", "description": "The personal refundable credit amount will be reduced for taxpayers with AGI higher than this threshold level.", "section_1": "Refundable Credits", "section_2": "Personal Refundable Credit", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -1062,18 +1062,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_credit_prt": { + "II_credit_prt": { "long_name": "Personal refundable credit phaseout rate", "description": "The personal refundable credit amount will be reduced at this rate for each dollar of AGI exceeding the _II_credit_ps threshold.", "section_1": "Refundable Credits", "section_2": "Personal Refundable Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1083,23 +1083,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_credit_nr": { + "II_credit_nr": { "long_name": "Personal nonrefundable credit maximum amount", "description": "This credit amount is not refundable and is phased out based on AGI.", "section_1": "Nonrefundable Credits", "section_2": "Personal Nonrefundable Credit", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -1114,23 +1114,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_credit_nr_ps": { + "II_credit_nr_ps": { "long_name": "Personal nonrefundable credit phaseout start", "description": "The personal nonrefundable credit amount will be reduced for taxpayers with AGI higher than this threshold level.", "section_1": "Nonrefundable Credits", "section_2": "Personal Nonrefundable Credit", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -1145,18 +1145,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_credit_nr_prt": { + "II_credit_nr_prt": { "long_name": "Personal nonrefundable credit phaseout rate", "description": "The personal nonrefundable credit amount will be reduced at this rate for each dollar of AGI exceeding the _II_credit_nr_ps threshold.", "section_1": "Nonrefundable Credits", "section_2": "Personal Nonrefundable Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1166,24 +1166,24 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Medical_frt": { + "ID_Medical_frt": { "long_name": "Floor (as a decimal fraction of AGI) for deductible medical expenses.", "description": "Taxpayers are eligible to deduct the portion of their medical expenses exceeding this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "Medical Expenses", "irs_ref": "Form 1040 Schedule A, line 3, in-line. ", "notes": "When using PUF data, lowering this parameter value may produce unexpected results because PUF e17500 variable is zero below the floor.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.100, 0.100, @@ -1199,22 +1199,22 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Medical_frt_add4aged": { + "ID_Medical_frt_add4aged": { "long_name": "Addon floor (as a decimal fraction of AGI) for deductible medical expenses for elderly filing units.", "description": "Elderly taxpayers have this fraction added to the value of the regular floor rate for deductible medical expenses. This fraction was -0.025 from 2013 to 2016, but that was temporary and it changed to zero beginning in 2017.", "section_1": "Itemized Deductions", "section_2": "Medical Expenses", "irs_ref": "Form 1040 Schedule A, line 3, in-line. ", "notes": "When using PUF data, changing this parameter value may produce unexpected results because PUF e17500 variable is zero below the floor.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [-0.025, -0.025, @@ -1228,18 +1228,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Medical_hc": { + "ID_Medical_hc": { "long_name": "Medical expense deduction haircut", "description": "This decimal fraction can be applied to limit the amount of medical expense deduction allowed.", "section_1": "Itemized Deductions", "section_2": "Medical Expenses", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1249,23 +1249,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Medical_c": { + "ID_Medical_c": { "long_name": "Ceiling on the amount of medical expense deduction allowed (dollars)", "description": "The amount of medical expense deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "Medical Expenses", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1280,18 +1280,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_StateLocalTax_hc": { + "ID_StateLocalTax_hc": { "long_name": "State and local income and sales taxes deduction haircut.", "description": "This decimal fraction reduces the state and local income and sales tax deduction.", "section_1": "Itemized Deductions", "section_2": "State And Local Income And Sales Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1301,18 +1301,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_StateLocalTax_crt": { + "ID_StateLocalTax_crt": { "long_name": "Ceiling (as a decimal fraction of AGI) for the combination of all state and local income and sales tax deductions.", "description": "The total deduction for state and local taxes is capped at this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "State And Local Income And Sales Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [9e99], "valid_values": {"min": 0, "max": 9e99}, @@ -1322,23 +1322,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_StateLocalTax_c": { + "ID_StateLocalTax_c": { "long_name": "Ceiling on the amount of state and local income and sales taxes deduction allowed (dollars)", "description": "The amount of state and local income and sales taxes deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "State And Local Income And Sales Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1353,18 +1353,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_RealEstate_hc": { + "ID_RealEstate_hc": { "long_name": "State, local, and foreign real estate taxes deduction haircut.", "description": "This decimal fraction reduces real estate taxes paid eligible to deduct in itemized deduction.", "section_1": "Itemized Deductions", "section_2": "State, Local, And Foreign Real Estate Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1374,18 +1374,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_RealEstate_crt": { + "ID_RealEstate_crt": { "long_name": "Ceiling (as a decimal fraction of AGI) for the combination of all state, local, and foreign real estate tax deductions.", "description": "The total deduction for all real estate taxes is capped at this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "State, Local, And Foreign Real Estate Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [9e99], "valid_values": {"min": 0, "max": 9e99}, @@ -1395,23 +1395,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_RealEstate_c": { + "ID_RealEstate_c": { "long_name": "Ceiling on the amount of state, local, and foreign real estate taxes deduction allowed (dollars)", "description": "The amount of real estate taxes deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "State, Local, And Foreign Real Estate Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1426,18 +1426,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_AllTaxes_hc": { + "ID_AllTaxes_hc": { "long_name": "State and local income, sales, and real estate tax deduction haircut.", "description": "This decimal fraction reduces all state and local taxes paid eligible to deduct in itemized deduction.", "section_1": "Itemized Deductions", "section_2": "State And Local Taxes And Real Estate Taxes", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1447,31 +1447,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_AllTaxes_c": { + "ID_AllTaxes_c": { "long_name": "Ceiling on the amount of state and local income, sales and real estate tax deductions allowed (dollars)", "description": "The amount of state and local income, sales and real estate tax deductions is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "State And Local Taxes And Real Estate Taxes", "irs_ref": "Form 1040 Schedule A, line 5e, in-line.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1494,18 +1494,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_InterestPaid_hc": { + "ID_InterestPaid_hc": { "long_name": "Interest paid deduction haircut", "description": "This decimal fraction can be applied to limit the amount of interest paid deduction allowed.", "section_1": "Itemized Deductions", "section_2": "Interest Paid", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1515,23 +1515,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_InterestPaid_c": { + "ID_InterestPaid_c": { "long_name": "Ceiling on the amount of interest paid deduction allowed (dollars)", "description": "The amount of interest paid deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "Interest Paid", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1546,31 +1546,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Charity_crt_all": { + "ID_Charity_crt_all": { "long_name": "Ceiling (as a decimal fraction of AGI) for all charitable contribution deductions", "description": "The total deduction for charity is capped at this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "Charity", "irs_ref": "Pub. 526, Limits on Deductions: 50% Limit Organizations. ", "notes": "When using PUF data, raising this parameter value may produce unexpected results because in PUF data the variables e19800 and e20100 are already capped.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.5, 0.5, @@ -1593,18 +1593,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Charity_crt_noncash": { + "ID_Charity_crt_noncash": { "long_name": "Ceiling (as a decimal fraction of AGI) for noncash charitable contribution deductions", "description": "The deduction for noncash charity contributions is capped at this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "Charity", "irs_ref": "Pub 526, Limits on Deductions: Special 30% Limit for Capital Gain Property. ", "notes": "When using PUF data, raising this parameter value may produce unexpected results because in PUF data the variables e19800 and e20100 are already capped.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.3], "valid_values": {"min": 0, "max": 0.3}, @@ -1614,18 +1614,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Charity_frt": { + "ID_Charity_frt": { "long_name": "Floor (as a decimal fraction of AGI) for deductible charitable contributions.", "description": "Taxpayers are eligible to deduct the portion of their charitable expense exceeding this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "Charity", "irs_ref": "", "notes": "This parameter allows for implementation of Option 52 from https://www.cbo.gov/sites/default/files/cbofiles/attachments/49638-BudgetOptions.pdf.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1635,18 +1635,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Charity_hc": { + "ID_Charity_hc": { "long_name": "Charity expense deduction haircut", "description": "This decimal fraction can be applied to limit the amount of charity expense deduction allowed.", "section_1": "Itemized Deductions", "section_2": "Charity", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -1656,23 +1656,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Charity_c": { + "ID_Charity_c": { "long_name": "Ceiling on the amount of charity expense deduction allowed (dollars)", "description": "The amount of charity expense deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "Charity", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1687,18 +1687,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Charity_f": { + "ID_Charity_f": { "long_name": "Floor on the amount of charity expense deduction allowed (dollars)", "description": "Only charitable giving in excess of this dollar amount is eligible for a deduction.", "section_1": "Itemized Deductions", "section_2": "Charity", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0]], "valid_values": {"min": 0, "max": 9e99}, @@ -1708,18 +1708,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Casualty_frt": { + "ID_Casualty_frt": { "long_name": "Floor (as a decimal fraction of AGI) for deductible casualty loss.", "description": "Taxpayers are eligible to deduct the portion of their gross casualty losses exceeding this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "Casualty", "irs_ref": "Form 4684, line 17, in-line.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.1], "valid_values": {"min": 0, "max": 1}, @@ -1729,31 +1729,31 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ID_Casualty_hc": { + "ID_Casualty_hc": { "long_name": "Casualty expense deduction haircut", "description": "This decimal fraction can be applied to limit the amount of casualty expense deduction allowed.", "section_1": "Itemized Deductions", "section_2": "Casualty", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -1776,23 +1776,23 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ID_Casualty_c": { + "ID_Casualty_c": { "long_name": "Ceiling on the amount of casualty expense deduction allowed (dollars)", "description": "The amount of casualty expense deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "Casualty", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1807,18 +1807,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ID_Miscellaneous_frt": { + "ID_Miscellaneous_frt": { "long_name": "Floor (as a decimal fraction of AGI) for deductible miscellaneous expenses.", "description": "Taxpayers are eligible to deduct the portion of their miscellaneous expense exceeding this fraction of AGI.", "section_1": "Itemized Deductions", "section_2": "Miscellaneous", "irs_ref": "Form 1040 Schedule A, line 16, instructions. ", "notes": "When using PUF data, lowering this parameter value may produce unexpected results because in PUF data the variable e20400 is zero below the floor.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.02], "valid_values": {"min": 0.02, "max": 1}, @@ -1828,31 +1828,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Miscellaneous_hc": { + "ID_Miscellaneous_hc": { "long_name": "Miscellaneous expense deduction haircut", "description": "This decimal fraction can be applied to limit the amount of miscellaneous expense deduction allowed.", "section_1": "Itemized Deductions", "section_2": "Miscellaneous", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -1875,23 +1875,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_Miscellaneous_c": { + "ID_Miscellaneous_c": { "long_name": "Ceiling on the amount of miscellaneous expense deduction allowed (dollars)", "description": "The amount of miscellaneous expense deduction is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "Miscellaneous", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -1906,31 +1906,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_ps": { + "ID_ps": { "long_name": "Itemized deduction phaseout AGI start (Pease provision)", "description": "The itemized deductions will be reduced for taxpayers with AGI higher than this level.", "section_1": "Itemized Deductions", "section_2": "Itemized Deduction Limitation", "irs_ref": "Form 1040 Schedule A, line 29, instructions.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[250000.0, 300000.0, 150000.0, 275000.0, 300000.0], [254200.0, 305050.0, 152525.0, 279650.0, 305050.0], @@ -1953,31 +1953,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_prt": { + "ID_prt": { "long_name": "Itemized deduction phaseout rate (Pease provision)", "description": "Taxpayers will not be eligible to deduct the full amount of itemized deduction if their AGI is above the phaseout start. The deductible portion would be decreased at this rate for each dollar exceeding the start.", "section_1": "Itemized Deductions", "section_2": "Itemized Deduction Limitation", "irs_ref": "Schedule A, line 29, instructions. ", "notes": "This phaseout rate cannot be lower than 0.03 for each dollar, due to limited data on non-itemizers.", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.03, 0.03, @@ -2000,31 +2000,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_crt": { + "ID_crt": { "long_name": "Itemized deduction maximum phaseout as a decimal fraction of total itemized deductions (Pease provision)", "description": "The phaseout amount is capped at this fraction of the original total deduction.", "section_1": "Itemized Deductions", "section_2": "Itemized Deduction Limitation", "irs_ref": "Form 1040 Schedule A, line 17, instructions. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.8, 0.8, @@ -2047,18 +2047,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_BenefitSurtax_trt": { + "ID_BenefitSurtax_trt": { "long_name": "Surtax rate on the benefits from specified itemized deductions", "description": "The benefit from specified itemized deductions exceeding the credit is taxed at this rate. A surtax rate of 1 strictly limits the benefit from specified itemized deductions to the specified credit. In http://www.nber.org/papers/w16921, Feldstein, Feenberg, and MacGuineas propose a credit of 2% of AGI against a 100% tax rate; in their proposal, however, a broader set of tax benefits, including the employer provided health exclusion, would be taxed.", "section_1": "Itemized Deductions", "section_2": "Surtax On Itemized Deduction Benefits Above An AGI Threshold", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -2068,18 +2068,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_BenefitSurtax_crt": { + "ID_BenefitSurtax_crt": { "long_name": "Credit on itemized deduction benefit surtax (decimal fraction of AGI)", "description": "The surtax on specified itemized deductions applies to benefits in excess of this fraction of AGI. In http://www.nber.org/papers/w16921, Feldstein, Feenberg, and MacGuineas propose a credit of 2% of AGI against a 100% tax rate; in their proposal, however, a broader set of tax benefits, including the employer provided health exclusion, would be taxed.", "section_1": "Itemized Deductions", "section_2": "Surtax On Itemized Deduction Benefits Above An AGI Threshold", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -2089,23 +2089,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_BenefitSurtax_em": { + "ID_BenefitSurtax_em": { "long_name": "Exemption for itemized deduction benefit surtax (dollar AGI threshold)", "description": "This amount is subtracted from itemized deduction benefits in the calculation of the itemized deduction benefit surtax. With _ID_BenefitSurtax_crt set to 0.0 and _ID_BenefitSurtax_trt set to 1.0, this amount serves as a dollar limit on the value of itemized deductions.", "section_1": "Itemized Deductions", "section_2": "Surtax On Itemized Deduction Benefits Above An AGI Threshold", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -2120,18 +2120,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_BenefitSurtax_Switch": { + "ID_BenefitSurtax_Switch": { "long_name": "Deductions subject to the surtax on itemized deduction benefits", "description": "The surtax on itemized deduction benefits applies to the benefits derived from the itemized deductions specified with this parameter.", "section_1": "Itemized Deductions", "section_2": "Surtax On Itemized Deduction Benefits Above An AGI Threshold", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "idedtype", - "col_label": ["medical", "statelocal", "realestate", "casualty", "misc", "interest", "charity"], + "vi_name": "idedtype", + "vi_vals": ["med", "sltx", "retx", "cas", "misc", "int", "char"], "value_type": "boolean", "value": [[true, true, true, true, true, true, true]], "valid_values": {"min": false, "max": true}, @@ -2141,18 +2141,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_BenefitCap_rt": { + "ID_BenefitCap_rt": { "long_name": "Ceiling on the benefits from itemized deductions; decimal fraction of total deductible expenses", "description": "The benefit from specified itemized deductions is capped at this percent of the total deductible expenses.", "section_1": "Itemized Deductions", "section_2": "Ceiling On The Benefit Of Itemized Deductions As A Percent Of Deductible Expenses", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -2162,18 +2162,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_BenefitCap_Switch": { + "ID_BenefitCap_Switch": { "long_name": "Deductions subject to the cap on itemized deduction benefits", "description": "The cap on itemized deduction benefits applies to the benefits derived from the itemized deductions specified with this parameter.", "section_1": "Itemized Deductions", "section_2": "Ceiling On The Benefit Of Itemized Deductions As A Percent Of Deductible Expenses", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "idedtype", - "col_label": ["medical", "statelocal", "realestate", "casualty", "misc", "interest", "charity"], + "vi_name": "idedtype", + "vi_vals": ["med", "sltx", "retx", "cas", "misc", "int", "char"], "value_type": "boolean", "value": [[true, true, true, true, true, true, true]], "valid_values": {"min": false, "max": true}, @@ -2183,23 +2183,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_c": { + "ID_c": { "long_name": "Ceiling on the amount of itemized deductions allowed (dollars)", "description": "The amount of itemized deductions is limited to this dollar amount.", "section_1": "Itemized Deductions", "section_2": "Ceiling On The Amount Of Itemized Deductions Allowed", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -2214,18 +2214,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_AmountCap_rt": { + "ID_AmountCap_rt": { "long_name": "Ceiling on the gross amount of itemized deductions allowed; decimal fraction of AGI", "description": "The gross allowable amount of specified itemized deductions is capped at this percent of AGI.", "section_1": "Itemized Deductions", "section_2": "Ceiling On The Amount Of Itemized Deductions Allowed", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [9e99], "valid_values": {"min": 0, "max": 9e99}, @@ -2235,18 +2235,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ID_AmountCap_Switch": { + "ID_AmountCap_Switch": { "long_name": "Deductions subject to the cap on itemized deduction benefits", "description": "The cap on itemized deduction benefits applies to the benefits derived from the itemized deductions specified with this parameter.", "section_1": "Itemized Deductions", "section_2": "Ceiling On The Amount Of Itemized Deductions Allowed", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "idedtype", - "col_label": ["medical", "statelocal", "realestate", "casualty", "misc", "interest", "charity"], + "vi_name": "idedtype", + "vi_vals": ["med", "sltx", "retx", "cas", "misc", "int", "char"], "value_type": "boolean", "value": [[true, true, true, true, true, true, true]], "valid_values": {"min": false, "max": true}, @@ -2256,18 +2256,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CG_rt1": { + "CG_rt1": { "long_name": "Long term capital gain and qualified dividends (regular/non-AMT) rate 1", "description": "The capital gain and dividends (stacked on top of regular income) that are below threshold 1 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 1040 Schedule D tax worksheet, line 20, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -2277,23 +2277,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CG_brk1": { + "CG_brk1": { "long_name": "Top of long-term capital gains and qualified dividends (regular/non-AMT) tax bracket 1", "description": "The gains and dividends (stacked on top of regular income) below this are taxed at capital gain rate 1.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 1040 Schedule D tax worksheet, line 15, in-line. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[36250.0, 72500.0, 36250.0, 48600.0, 72500.0], [36900.0, 73800.0, 36900.0, 49400.0, 73800.0], @@ -2301,25 +2301,25 @@ [37650.0, 75300.0, 37650.0, 50400.0, 75300.0], [37950.0, 75900.0, 37950.0, 50800.0, 75900.0], [38600.0, 77200.0, 38600.0, 51700.0, 77200.0]], - "valid_values": {"min": 0, "max": "_CG_brk2"}, + "valid_values": {"min": 0, "max": "CG_brk2"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _CG_brk2", + "invalid_maxmsg": "for CG_brk2", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_CG_rt2": { + "CG_rt2": { "long_name": "Long term capital gain and qualified dividends (regular/non-AMT) rate 2", "description": "The capital gain and dividends (stacked on top of regular income) that are below threshold 2 and above threshold 1 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 1040 Schedule D tax worksheet, line 29, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.15], "valid_values": {"min": 0, "max": 1}, @@ -2329,23 +2329,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CG_brk2": { + "CG_brk2": { "long_name": "Top of long-term capital gains and qualified dividends (regular/non-AMT) tax bracket 2", "description": "The gains and dividends (stacked on top of regular income) below this and above top of bracket 1 are taxed at capital gain rate 2.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 1040 Schedule D tax worksheet, line 24, in-line. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[400000.0, 450000.0, 225000.0, 425000.0, 450000.0], [406750.0, 457600.0, 228800.0, 432200.0, 457600.0], @@ -2353,25 +2353,25 @@ [415050.0, 466950.0, 233475.0, 441000.0, 466950.0], [418400.0, 470700.0, 235350.0, 444550.0, 470700.0], [425800.0, 479000.0, 239500.0, 452400.0, 479000.0]], - "valid_values": {"min": "_CG_brk1", "max": "_CG_brk3"}, - "invalid_minmsg": "for _CG_brk1", - "invalid_maxmsg": "for _CG_brk3", + "valid_values": {"min": "CG_brk1", "max": "CG_brk3"}, + "invalid_minmsg": "for CG_brk1", + "invalid_maxmsg": "for CG_brk3", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_CG_rt3": { + "CG_rt3": { "long_name": "Long term capital gain and qualified dividends (regular/non-AMT) rate 3", "description": "The capital gain and dividends (stacked on top of regular income) that are above threshold 2 and below threshold 3 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 1040 Schedule D tax worksheet, line 32, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.20], "valid_values": {"min": 0, "max": 1}, @@ -2381,23 +2381,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CG_brk3": { + "CG_brk3": { "long_name": "Top of long-term capital gains and qualified dividend tax (regular/non-AMT) bracket 3", "description": "The gains and dividends (stacked on top of regular income) below this and above top of bracket 2 are taxed at the capital gain rate 3; above this they are taxed at capital gain rate 4. Default value is essentially infinity.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 1040 Schedule D tax worksheet, line 24, in-line. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -2405,25 +2405,25 @@ [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99]], - "valid_values": {"min": "_CG_brk2", "max": 9e99}, - "invalid_minmsg": "for _CG_brk2", + "valid_values": {"min": "CG_brk2", "max": 9e99}, + "invalid_minmsg": "for CG_brk2", "invalid_maxmsg": "", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_CG_rt4": { + "CG_rt4": { "long_name": "Long term capital gain and qualified dividends (regular/non-AMT) rate 4", "description": "The capital gain and dividends (stacked on top of regular income) that are above threshold 3 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "Regular - Long Term Capital Gains And Qualified Dividends", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -2433,18 +2433,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_rt1": { + "AMT_CG_rt1": { "long_name": "Long term capital gain and qualified dividends (AMT) rate 1", "description": "Capital gain and qualified dividends (stacked on top of regular income) below threshold 1 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 6251, line 47, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -2454,23 +2454,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_brk1": { + "AMT_CG_brk1": { "long_name": "Top of long-term capital gains and qualified dividends (AMT) tax bracket 1", "description": "The gains and dividends, stacked last, of AMT taxable income below this are taxed at AMT capital gain rate 1.", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 6251, line 19, in-line. ", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[36250.0, 72500.0, 36250.0, 48600.0, 72500.0], [36900.0, 73800.0, 36900.0, 49400.0, 73800.0], @@ -2478,25 +2478,25 @@ [37650.0, 75300.0, 37650.0, 50400.0, 75300.0], [37950.0, 75900.0, 37950.0, 50800.0, 75900.0], [38600.0, 77200.0, 38600.0, 51700.0, 77200.0]], - "valid_values": {"min": 0, "max": "_AMT_CG_brk2"}, + "valid_values": {"min": 0, "max": "AMT_CG_brk2"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _AMT_CG_brk2", + "invalid_maxmsg": "for AMT_CG_brk2", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_rt2": { + "AMT_CG_rt2": { "long_name": "Long term capital gain and qualified dividends (AMT) rate 2", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "description": "Capital gain and qualified dividend (stacked on top of regular income) below threshold 2 and above threshold 1 are taxed at this rate.", "irs_ref": "Form 6251, line 31, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.15], "valid_values": {"min": 0, "max": 1}, @@ -2506,23 +2506,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_brk2": { + "AMT_CG_brk2": { "long_name": "Top of long-term capital gains and qualified dividends (AMT) tax bracket 2", "description": "The gains and dividends, stacked last, of AMT taxable income below this threshold and above bracket 1 are taxed at AMT capital gain rate 2.", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "notes": "", "irs_ref": "Form 6251, line 25, in-line. ", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[400000.0, 450000.0, 225000.0, 425000.0, 450000.0], [406750.0, 457600.0, 228800.0, 432200.0, 457600.0], @@ -2530,25 +2530,25 @@ [415050.0, 466950.0, 233475.0, 441000.0, 466950.0], [418400.0, 470700.0, 235350.0, 444550.0, 470700.0], [425800.0, 479000.0, 239500.0, 452400.0, 479000.0]], - "valid_values": {"min": "_AMT_CG_brk1", "max": "_AMT_CG_brk3"}, - "invalid_minmsg": "for _AMT_CG_brk1", - "invalid_maxmsg": "for _AMT_CG_brk3", + "valid_values": {"min": "AMT_CG_brk1", "max": "AMT_CG_brk3"}, + "invalid_minmsg": "for AMT_CG_brk1", + "invalid_maxmsg": "for AMT_CG_brk3", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_rt3": { + "AMT_CG_rt3": { "long_name": "Long term capital gain and qualified dividends (AMT) rate 3", "description": "The capital gain and qualified dividend (stacked on top of regular income) above threshold 2 and below threshold 3 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "irs_ref": "Form 6251, line 34, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.20], "valid_values": {"min": 0, "max": 1}, @@ -2558,23 +2558,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_brk3": { + "AMT_CG_brk3": { "long_name": "Long term capital gain and qualified dividends (AMT) threshold 3", "description": "The gains and dividends, stacked last, of AMT taxable income below this and above bracket 2 are taxed at capital gain rate 3; above thisthey are taxed at AMT capital gain rate 4. Default value is essentially infinity.", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -2582,25 +2582,25 @@ [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99]], - "valid_values": {"min": "_AMT_CG_brk2", "max": 9e99}, - "invalid_minmsg": "for _AMT_CG_brk2", + "valid_values": {"min": "AMT_CG_brk2", "max": 9e99}, + "invalid_minmsg": "for AMT_CG_brk2", "invalid_maxmsg": "", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_AMT_CG_rt4": { + "AMT_CG_rt4": { "long_name": "Long term capital gain and qualified dividends (AMT) rate 4", "description": "The capital gain and dividends (stacked on top of regular income) that are above threshold 3 are taxed at this rate.", "section_1": "Capital Gains And Dividends", "section_2": "AMT - Long Term Capital Gains And Qualified Dividends", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -2610,18 +2610,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CG_nodiff": { + "CG_nodiff": { "long_name": "Long term capital gains and qualified dividends taxed no differently than regular taxable income", "description": "Specifies whether or not long term capital gains and qualified dividends are taxed like regular taxable income.", "section_1": "Capital Gains And Dividends", "section_2": "Tax All Capital Gains And Dividends The Same As Regular Taxable Income", "irs_ref": "Current-law value is zero implying different tax treatment in Schedule D and AMT; a value of one implies same tax treatment in both regular and alternative minimum tax rules, but the same treatment can differ for regular and AMT.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -2631,23 +2631,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CG_ec": { + "CG_ec": { "long_name": "Dollar amount of all capital gains and qualified dividends that are excluded from AGI.", "description": "Positive value used only if long term capital gains and qualified dividends taxed no differently than regular taxable income.", "section_1": "Capital Gains And Dividends", "section_2": "Tax All Capital Gains And Dividends The Same As Regular Taxable Income", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -2662,18 +2662,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CG_reinvest_ec_rt": { + "CG_reinvest_ec_rt": { "long_name": "Fraction of all capital gains and qualified dividends in excess of the dollar exclusion that are excluded from AGI.", "description": "Positive value used only if long term capital gains and qualified dividends taxed no differently than regular taxable income. To limit the exclusion to capital gains and dividends invested within one year, set to statutory exclusion rate times the fraction of capital gains and qualified dividends in excess of the exclusion that are assumed to be reinvested within the year.", "section_1": "Capital Gains And Dividends", "section_2": "Tax All Capital Gains And Dividends The Same As Regular Taxable Income", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -2683,31 +2683,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_rt1": { + "II_rt1": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 1", "description": "The lowest tax rate, applied to the portion of taxable income below tax bracket 1.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.10, 0.10, @@ -2730,31 +2730,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk1": { + "II_brk1": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket (upper threshold) 1", "description": "Taxable income below this threshold is taxed at tax rate 1.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 44, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[8925.00, 17850.00, 8925.00, 12750.00, 17850.00], [9075.00, 18150.00, 9075.00, 12950.00, 18150.00], @@ -2770,38 +2770,38 @@ [10854.5, 21709.0, 10854.5, 15498.29, 21709.0], [11083.53, 22167.06, 11083.53, 15825.3, 22167.06], [11285.0, 22569.0, 11285.0, 16156.0, 22569.0]], - "valid_values": {"min": 0, "max": "_II_brk2"}, + "valid_values": {"min": 0, "max": "II_brk2"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _II_brk2", + "invalid_maxmsg": "for II_brk2", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt2": { + "II_rt2": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 2", "description": "The second lowest tax rate, applied to the portion of taxable income below tax bracket 2 and above tax bracket 1.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.15, 0.15, @@ -2824,31 +2824,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk2": { + "II_brk2": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket (upper threshold) 2", "description": "Income below this threshold and above tax bracket 1 is taxed at tax rate 2.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[36250.00, 72500.00, 36250.00, 48600.00, 72500.00], [36900.00, 73800.00, 36900.00, 49400.00, 73800.00], @@ -2864,38 +2864,38 @@ [44101.74, 88203.48, 44101.74, 59030.24, 88203.48], [45032.29, 90064.58, 45032.29, 60275.78, 90064.58], [45926.0, 91851.0, 45926.0, 61476.0, 91851.0]], - "valid_values": {"min": "_II_brk1", "max": "_II_brk3"}, - "invalid_minmsg": "for _II_brk1", - "invalid_maxmsg": "for _II_brk3", + "valid_values": {"min": "II_brk1", "max": "II_brk3"}, + "invalid_minmsg": "for II_brk1", + "invalid_maxmsg": "for II_brk3", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt3": { + "II_rt3": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 3", "description": "The third lowest tax rate, applied to the portion of taxable income below tax bracket 3 and above tax bracket 2.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.25, 0.25, @@ -2918,31 +2918,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk3": { + "II_brk3": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket (upper threshold) 3", "description": "Income below this threshold and above tax bracket 2 is taxed at tax rate 3.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[87850.00, 146400.00, 73200.00, 125450.00, 146400.00], [89350.00, 148850.00, 74425.00, 127550.00, 148850.00], @@ -2959,38 +2959,38 @@ [94015.34, 188030.68, 94015.34, 94015.34, 188030.68], [95999.06, 191998.13, 95999.06, 95999.06, 191998.13], [111214.0, 185275.0, 92638.0, 158773.0, 185275.0]], - "valid_values": {"min": "_II_brk2", "max": "_II_brk4"}, - "invalid_minmsg": "for _II_brk2", - "invalid_maxmsg": "for _II_brk4", + "valid_values": {"min": "II_brk2", "max": "II_brk4"}, + "invalid_minmsg": "for II_brk2", + "invalid_maxmsg": "for II_brk4", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt4": { + "II_rt4": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 4", "description": "The tax rate applied to the portion of taxable income below tax bracket 4 and above tax bracket 3.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.28, 0.28, @@ -3013,31 +3013,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk4": { + "II_brk4": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket (upper threshold) 4", "description": "Income below this threshold and above tax bracket 3 is taxed at tax rate 4.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Tax Rate Schedules).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[183250.00, 223050.00, 111525.00, 203150.00, 223050.00], [186350.00, 226850.00, 113425.00, 206600.00, 226850.00], @@ -3053,38 +3053,38 @@ [179483.83, 358967.66, 179483.83, 179483.83, 358967.66], [183270.94, 366541.88, 183270.94, 183270.94, 366541.88], [231927.0, 282391.0, 141195.0, 257159.0, 282391.0]], - "valid_values": {"min": "_II_brk3", "max": "_II_brk5"}, - "invalid_minmsg": "for _II_brk3", - "invalid_maxmsg": "for _II_brk5", + "valid_values": {"min": "II_brk3", "max": "II_brk5"}, + "invalid_minmsg": "for II_brk3", + "invalid_maxmsg": "for II_brk5", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt5": { + "II_rt5": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 5", "description": "The third highest tax rate, applied to the portion of taxable income below tax bracket 5 and above tax bracket 4.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.33, 0.33, @@ -3107,31 +3107,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk5": { + "II_brk5": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket (upper threshold) 5", "description": "Income below this threshold and above tax bracket 4 is taxed at tax rate 5.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[398350.00, 398350.00, 199175.00, 398350.00, 398350.00], [405100.00, 405100.00, 202550.00, 405100.00, 405100.00], @@ -3147,38 +3147,38 @@ [227915.98, 455831.95, 227915.98, 227915.98, 455831.95], [232725.0, 465450.01, 232725.0, 232725.0, 465450.01], [504273.0, 504273.0, 252137.0, 504273.0, 504273.0]], - "valid_values": {"min": "_II_brk4", "max": "_II_brk6"}, - "invalid_minmsg": "for _II_brk4", - "invalid_maxmsg": "for _II_brk6", + "valid_values": {"min": "II_brk4", "max": "II_brk6"}, + "invalid_minmsg": "for II_brk4", + "invalid_maxmsg": "for II_brk6", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt6": { + "II_rt6": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 6", "description": "The second higher tax rate, applied to the portion of taxable income below tax bracket 6 and above tax bracket 5.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.35, 0.35, @@ -3201,31 +3201,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk6": { + "II_brk6": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket 6", "description": "Income below this threshold and above tax bracket 5 is taxed at tax rate 6.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[400000.00, 450000.00, 225000.00, 425000.00, 450000.00], [406750.00, 457600.00, 228800.00, 432200.00, 457600.00], @@ -3241,38 +3241,38 @@ [569789.94, 683747.93, 341873.96, 569789.94, 683747.93], [581812.51, 698175.01, 349087.5, 581812.51, 698175.01], [506331.0, 569622.0, 284811.0, 537976.0, 569622.0]], - "valid_values": {"min": "_II_brk5", "max": "_II_brk7"}, - "invalid_minmsg": "for _II_brk5", - "invalid_maxmsg": "for _II_brk7", + "valid_values": {"min": "II_brk5", "max": "II_brk7"}, + "invalid_minmsg": "for II_brk5", + "invalid_maxmsg": "for II_brk7", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt7": { + "II_rt7": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 7", "description": "The tax rate applied to the portion of taxable income below tax bracket 7 and above tax bracket 6.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.396, 0.396, @@ -3295,31 +3295,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_II_brk7": { + "II_brk7": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax bracket 7", "description": "Income below this threshold and above tax bracket 6 is taxed at tax rate 7; income above this threshold is taxed at tax rate 8. Default value is essentially infinity.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -3335,25 +3335,25 @@ [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99]], - "valid_values": {"min": "_II_brk6", "max": 9e99}, - "invalid_minmsg": "for _II_brk6", + "valid_values": {"min": "II_brk6", "max": 9e99}, + "invalid_minmsg": "for II_brk6", "invalid_maxmsg": "", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_II_rt8": { + "II_rt8": { "long_name": "Personal income (regular/non-AMT/non-pass-through) tax rate 8", "description": "The tax rate applied to the portion of taxable income above tax bracket 7.", "section_1": "Personal Income", "section_2": "Regular: Non-AMT, Non-Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -3363,31 +3363,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt1": { + "PT_rt1": { "long_name": "Pass-through income tax rate 1", "description": "The lowest tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 1.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.10, 0.10, @@ -3410,31 +3410,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk1": { + "PT_brk1": { "long_name": "Pass-through income tax bracket (upper threshold) 1", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold is taxed at tax rate 1.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[8925.00, 17850.00, 8925.00, 12750.00, 17850.00], [9075.00, 18150.00, 9075.00, 12950.00, 18150.00], @@ -3450,38 +3450,38 @@ [10854.5, 21709.0, 10854.5, 15498.29, 21709.0], [11083.53, 22167.06, 11083.53, 15825.3, 22167.06], [11285.0, 22569.0, 11285.0, 16156.0, 22569.0]], - "valid_values": {"min": 0, "max": "_PT_brk2"}, + "valid_values": {"min": 0, "max": "PT_brk2"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _PT_brk2", + "invalid_maxmsg": "for PT_brk2", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt2": { + "PT_rt2": { "long_name": "Pass-through income tax rate 2", "description": "The second lowest tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 2 and above tax bracket 1.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.15, 0.15, @@ -3504,31 +3504,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk2": { + "PT_brk2": { "long_name": "Pass-through income tax bracket (upper threshold) 2", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold and above tax bracket 1 is taxed at tax rate 2.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[36250.00, 72500.00, 36250.00, 48600.00, 72500.00], [36900.00, 73800.00, 36900.00, 49400.00, 73800.00], @@ -3544,38 +3544,38 @@ [44101.74, 88203.48, 44101.74, 59030.24, 88203.48], [45032.29, 90064.58, 45032.29, 60275.78, 90064.58], [45926.0, 91851.0, 45926.0, 61476.0, 91851.0]], - "valid_values": {"min": "_PT_brk1", "max": "_PT_brk3"}, - "invalid_minmsg": "for _PT_brk1", - "invalid_maxmsg": "for _PT_brk3", + "valid_values": {"min": "PT_brk1", "max": "PT_brk3"}, + "invalid_minmsg": "for PT_brk1", + "invalid_maxmsg": "for PT_brk3", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt3": { + "PT_rt3": { "long_name": "Pass-through income tax rate 3", "description": "The third lowest tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 3 and above tax bracket 2.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.25, 0.25, @@ -3598,31 +3598,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk3": { + "PT_brk3": { "long_name": "Pass-through income tax bracket (upper threshold) 3", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold and above tax bracket 2 is taxed at tax rate 3.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[87850.00, 146400.00, 73200.00, 125450.00, 146400.00], [89350.00, 148850.00, 74425.00, 127550.00, 148850.00], @@ -3638,38 +3638,38 @@ [94015.34, 188030.68, 94015.34, 94015.34, 188030.68], [95999.06, 191998.13, 95999.06, 95999.06, 191998.13], [111214.0, 185275.0, 92638.0, 158773.0, 185275.0]], - "valid_values": {"min": "_PT_brk2", "max": "_PT_brk4"}, - "invalid_minmsg": "for _PT_brk2", - "invalid_maxmsg": "for _PT_brk4", + "valid_values": {"min": "PT_brk2", "max": "PT_brk4"}, + "invalid_minmsg": "for PT_brk2", + "invalid_maxmsg": "for PT_brk4", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt4": { + "PT_rt4": { "long_name": "Pass-through income tax rate 4", "description": "The tax rate applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 4 and above tax bracket 3.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.28, 0.28, @@ -3692,31 +3692,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk4": { + "PT_brk4": { "long_name": "Pass-through income tax bracket (upper threshold) 4", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold and above tax bracket 3 is taxed at tax rate 4.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[183250.00, 223050.00, 111525.00, 203150.00, 223050.00], [186350.00, 226850.00, 113425.00, 206600.00, 226850.00], @@ -3732,38 +3732,38 @@ [179483.83, 358967.66, 179483.83, 179483.83, 358967.66], [183270.94, 366541.88, 183270.94, 183270.94, 366541.88], [231927.0, 282391.0, 141195.0, 257159.0, 282391.0]], - "valid_values": {"min": "_PT_brk3", "max": "_PT_brk5"}, - "invalid_minmsg": "for _PT_brk3", - "invalid_maxmsg": "for _PT_brk5", + "valid_values": {"min": "PT_brk3", "max": "PT_brk5"}, + "invalid_minmsg": "for PT_brk3", + "invalid_maxmsg": "for PT_brk5", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt5": { + "PT_rt5": { "long_name": "Pass-through income tax rate 5", "description": "The third highest tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 5 and above tax bracket 4.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.33, 0.33, @@ -3786,31 +3786,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk5": { + "PT_brk5": { "long_name": "Pass-through income tax bracket (upper threshold) 5", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold and above tax bracket 4 is taxed at tax rate 5.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[398350.00, 398350.00, 199175.00, 398350.00, 398350.00], [405100.00, 405100.00, 202550.00, 405100.00, 405100.00], @@ -3826,38 +3826,38 @@ [227915.98, 455831.95, 227915.98, 227915.98, 455831.95], [232725.0, 465450.01, 232725.0, 232725.0, 465450.01], [504273.0, 504273.0, 252137.0, 504273.0, 504273.0]], - "valid_values": {"min": "_PT_brk4", "max": "_PT_brk6"}, - "invalid_minmsg": "for _PT_brk4", - "invalid_maxmsg": "for _PT_brk6", + "valid_values": {"min": "PT_brk4", "max": "PT_brk6"}, + "invalid_minmsg": "for PT_brk4", + "invalid_maxmsg": "for PT_brk6", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt6": { + "PT_rt6": { "long_name": "Pass-through income tax rate 6", "description": "The second higher tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 6 and above tax bracket 5.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.35, 0.35, @@ -3880,31 +3880,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk6": { + "PT_brk6": { "long_name": "Pass-through income tax bracket (upper threshold) 6", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold and above tax bracket 5 is taxed at tax rate 6.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[400000.00, 450000.00, 225000.00, 425000.00, 450000.00], [406750.00, 457600.00, 228800.00, 432200.00, 457600.00], @@ -3920,38 +3920,38 @@ [569789.94, 683747.93, 341873.96, 569789.94, 683747.93], [581812.51, 698175.01, 349087.5, 581812.51, 698175.01], [506331.0, 569622.0, 284811.0, 537976.0, 569622.0]], - "valid_values": {"min": "_PT_brk5", "max": "_PT_brk7"}, - "invalid_minmsg": "for _PT_brk5", - "invalid_maxmsg": "for _PT_brk7", + "valid_values": {"min": "PT_brk5", "max": "PT_brk7"}, + "invalid_minmsg": "for PT_brk5", + "invalid_maxmsg": "for PT_brk7", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt7": { + "PT_rt7": { "long_name": "Pass-through income tax rate 7", "description": "The highest tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations below tax bracket 7 and above tax bracket 6.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "Form 1040, line 11, instruction (Schedule XYZ)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.396, 0.396, @@ -3974,31 +3974,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_brk7": { + "PT_brk7": { "long_name": "Extra pass-through income tax bracket", "description": "Income from sole proprietorships, partnerships and S-corporations below this threshold and above tax bracket 6 is taxed at tax rate 7. Default value is essentially infinity.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -4014,25 +4014,25 @@ [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99]], - "valid_values": {"min": "_PT_brk6", "max": 9e99}, - "invalid_minmsg": "for _PT_brk6", + "valid_values": {"min": "PT_brk6", "max": 9e99}, + "invalid_minmsg": "for PT_brk6", "invalid_maxmsg": "", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_PT_rt8": { + "PT_rt8": { "long_name": "Extra pass-through income tax rate", "description": "The extra tax rate, applied to the portion of income from sole proprietorships, partnerships and S-corporations above the tax bracket 7.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -4042,18 +4042,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_EligibleRate_active": { + "PT_EligibleRate_active": { "long_name": "Share of active business income eligible for PT rate schedule", "description": "Eligibility rate of active business income for separate pass-through rates.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "Active business income defined as e00900 + e26270", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1.0], "valid_values": {"min": 0, "max": 1}, @@ -4063,18 +4063,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_EligibleRate_passive": { + "PT_EligibleRate_passive": { "long_name": "Share of passive business income eligible for PT rate schedule", - "description": "Eligibility rate of passive business income for separate pass-through rates.", + "description": "Eligibility rate of passive business income for marsep pass-through rates.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "Passive business income defined as e02000 - e26270", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -4084,18 +4084,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_PT_wages_active_income": { + "PT_wages_active_income": { "long_name": "Wages included in (positive) active business income eligible for PT rates", "description": "Whether active business income eligibility base for PT schedule for includes wages.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "Only applies if active business income is positive", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -4105,18 +4105,18 @@ "compatible_data": {"puf": false, "cps": false} }, - "_PT_top_stacking": { + "PT_top_stacking": { "long_name": "PT taxable income stacked on top of regular taxable income", "description": "Whether taxable income eligible for PT rate schedule is stacked on top of regular taxable income.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [true], "valid_values": {"min": false, "max": true}, @@ -4126,31 +4126,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_excl_rt": { + "PT_excl_rt": { "long_name": "Pass-through income exclusion rate", "description": "Fraction of qualified business income excluded from taxable income.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "Applies to e00900 + e26270", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -4173,31 +4173,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_excl_wagelim_rt": { + "PT_excl_wagelim_rt": { "long_name": "Wage limit rate on pass-through income exclusion", "description": "If taxpayer has partnership/S-corporation income, the amount of business income excluded from taxable income may not exceed this fraction of wages.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "", - "col_label": "", + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [9e99, 9e99, @@ -4220,31 +4220,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_excl_wagelim_thd": { + "PT_excl_wagelim_thd": { "long_name": "Phase-in threshold of wage limit on pass-through income exclusion", "description": "If taxpayer has partnership/S-corporation income, the amount of business income excluded from taxable income is limited by wages if taxable income exceeds this threshold.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.00, 0.00, 0.00, 0.00, 0.00], [0.00, 0.00, 0.00, 0.00, 0.00], @@ -4267,31 +4267,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_PT_excl_wagelim_prt": { + "PT_excl_wagelim_prt": { "long_name": "Phase-in rate of wage limit on pass-through income exclusion", "description": "If taxpayer has partnership/S-corporation income, the wage limitation on the amount of business income excluded from taxable income is phased in at this rate.", "section_1": "Personal Income", "section_2": "Pass-Through", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], - "indexable": false, - "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], + "indexable": false, + "indexed": false, + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -4314,7 +4314,7 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_em": { + "AMT_em": { "long_name": "AMT exemption amount", "description": "The amount of AMT taxable income exempted from AMT.", "section_1": "Personal Income", @@ -4322,24 +4322,24 @@ "section_3": "Exemption", "irs_ref": "Form 1040 (Schedule 2), line 45, instruction (Worksheet).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[51900.00, 80800.00, 40400.00, 51900.00, 80800.00], [52800.00, 82100.00, 41050.00, 52800.00, 82100.00], @@ -4362,7 +4362,7 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_prt": { + "AMT_prt": { "long_name": "AMT exemption phaseout rate", "description": "AMT exemption will decrease at this rate for each dollar of AMT taxable income exceeding AMT phaseout start.", "section_1": "Personal Income", @@ -4370,11 +4370,11 @@ "section_3": "Exemption", "irs_ref": "Form 1040 (Schedule 2), line 45, instruction (Worksheet).", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.25], "valid_values": {"min": 0, "max": 1}, @@ -4384,7 +4384,7 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_em_ps": { + "AMT_em_ps": { "long_name": "AMT exemption phaseout start", "description": "AMT exemption starts to decrease when AMT taxable income goes beyond this threshold.", "section_1": "Personal Income", @@ -4392,24 +4392,24 @@ "section_3": "Exemption", "irs_ref": "Form 1040 (Schedule 2), line 45, instruction (Worksheet).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[115400.00, 153900.00, 76950.00, 115400.00, 153900.00], [117300.00, 156500.00, 78250.00, 117300.00, 156500.00], @@ -4432,23 +4432,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_child_em": { + "AMT_child_em": { "long_name": "Child AMT exemption additional income base", "description": "The child's AMT exemption is capped by this amount plus the child's earned income.", "section_1": "", "section_2": "", "irs_ref": "Form 6251, line 5, instruction.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [7150.0, 7250.0, @@ -4463,18 +4463,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_child_em_c_age": { + "AMT_child_em_c_age": { "long_name": "Age ceiling for special AMT exemption", "description": "Individuals under this age must use the child AMT exemption rules.", "section_1": "", "section_2": "", "irs_ref": "Form 6251, line 5, instruction.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "integer", "value": [18], "valid_values": {"min": 0, "max": 30}, @@ -4484,7 +4484,7 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_rt1": { + "AMT_rt1": { "long_name": "AMT rate 1", "description": "The tax rate applied to the portion of AMT taxable income below the surtax threshold, AMT bracket 1.", "section_1": "Personal Income", @@ -4492,11 +4492,11 @@ "section_3": "Tax rates", "irs_ref": "Form 6251, line 7, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.26], "valid_values": {"min": 0, "max": 1}, @@ -4506,7 +4506,7 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_brk1": { + "AMT_brk1": { "long_name": "AMT bracket 1 (upper threshold)", "description": "AMT taxable income below this is subject to AMT rate 1 and above it is subject to AMT rate 1 + the additional AMT rate.", "section_1": "Personal Income", @@ -4514,16 +4514,16 @@ "section_3": "Tax rates", "irs_ref": "Form 6251, line 7, instruction.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [179500.0, 182500.0, @@ -4538,7 +4538,7 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_rt2": { + "AMT_rt2": { "long_name": "Additional AMT rate for AMT taxable income above AMT bracket 1", "description": "The additional tax rate applied to the portion of AMT income above the AMT bracket 1.", "section_1": "Personal Income", @@ -4546,11 +4546,11 @@ "section_3": "Tax rates", "irs_ref": "Form 6251, line 7, in-line. ", "notes": "This is the additional tax rate (on top of AMT rate 1) for AMT income above AMT bracket 1.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.02], "valid_values": {"min": 0, "max": 1}, @@ -4560,31 +4560,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AMT_em_pe": { + "AMT_em_pe": { "long_name": "AMT exemption phaseout ending AMT taxable income for Married filling Separately", "description": "The AMT exemption is entirely disallowed beyond this AMT taxable income level for individuals who are married but filing separately.", "section_1": "", "section_2": "", "irs_ref": "Form 6251, line 4, instruction.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [238550.0, 242450.0, @@ -4607,18 +4607,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CDCC_c": { + "CDCC_c": { "long_name": "Maximum child & dependent care credit per dependent", "description": "The maximum amount of credit allowed for each qualifying dependent.", "section_1": "Nonrefundable Credits", "section_2": "Child And Dependent Care", "irs_ref": "Form 2441, line 3, in-line.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [3000.0], "valid_values": {"min": 0, "max": 3000}, @@ -4628,17 +4628,17 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CDCC_ps": { + "CDCC_ps": { "long_name": "Child & dependent care credit phaseout start", "description": "For taxpayers with AGI over this amount, the credit is reduced by one percentage point each $2000 of AGI over this amount.", "section_1": "Nonrefundable Credits", "section_2": "Child And Dependent Care", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [15000.0], "valid_values": {"min": 0, "max": 9e99}, @@ -4648,18 +4648,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CDCC_crt": { + "CDCC_crt": { "long_name": "Child & dependent care credit phaseout percentage rate ceiling", "description": "The maximum percentage rate in the AGI phaseout; this percentage rate decreases as AGI rises above the _CDCC_ps level.", "section_1": "Nonrefundable Credits", "section_2": "Child And Dependent Care", "irs_ref": "Form 2241, line 8, in-line.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [35.0], "valid_values": {"min": 0, "max": 100}, @@ -4669,31 +4669,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_c": { + "CTC_c": { "long_name": "Maximum nonrefundable child tax credit per child", "description": "The maximum nonrefundable credit allowed for each child.", "section_1": "Child/Dependent Credits", "section_2": "Child Tax Credit", "irs_ref": "Form 1040, line 12, worksheet, line 1.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1000.0, 1000.0, @@ -4716,18 +4716,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_c_under5_bonus": { + "CTC_c_under5_bonus": { "long_name": "Bonus child tax credit maximum for qualifying children under five", "description": "The maximum amount of child tax credit allowed for each child is increased by this amount for qualifying children under 5 years old.", "section_1": "Child/Dependent Credits", "section_2": "Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 9e99}, @@ -4737,31 +4737,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_ps": { + "CTC_ps": { "long_name": "Child tax credit phaseout MAGI start", "description": "Child tax credit begins to decrease when MAGI is above this level; read descriptions of the dependent credit amounts for how they phase out when MAGI is above this level.", "section_1": "Child/Dependent Credits", "section_2": "Child Tax Credit", "irs_ref": "Form 1040, line 12, worksheet, line 5.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[75000.0, 110000.0, 55000.0, 75000.0, 75000.0], [75000.0, 110000.0, 55000.0, 75000.0, 75000.0], @@ -4784,18 +4784,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_prt": { + "CTC_prt": { "long_name": "Child and dependent tax credit phaseout rate", "description": "The amount of the credit starts to decrease at this rate if MAGI is higher than child tax credit phaseout start.", "section_1": "Child/Dependent Credits", "section_2": "Child Tax Credit", "irs_ref": "Form 1040, line 12, instruction (child tax credit worksheet, line 7)", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.05], "valid_values": {"min": 0, "max": 1}, @@ -4805,31 +4805,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ACTC_c": { + "ACTC_c": { "long_name": "Maximum refundable additional child tax credit", "description": "This refundable credit is applied to child dependents and phases out exactly like the CTC amount.", "section_1": "Child/Dependent Credits", "section_2": "Additional Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [1000.0, 1000.0, @@ -4845,38 +4845,38 @@ 1500.0, 1600.0, 1000.0], - "valid_values": {"min": 0, "max": "_CTC_c"}, + "valid_values": {"min": 0, "max": "CTC_c"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _CTC_c", + "invalid_maxmsg": "for CTC_c", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_ODC_c": { + "ODC_c": { "long_name": "Maximum nonrefundable other-dependent credit", "description": "This nonrefundable credit is applied to non-child dependents and phases out along with the CTC amount.", "section_1": "Child/Dependent Credits", "section_2": "Other Dependent Tax Credit", "irs_ref": "Form 1040, line 12, instruction (child tax credit worksheet, line 2)", "notes": "Became current-law policy with passage of TCJA", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -4899,18 +4899,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_NIIT_thd": { + "NIIT_thd": { "long_name": "Net Investment Income Tax modified AGI threshold", "description": "If modified AGI is more than this threshold, filing unit is subject to the Net Investment Income Tax.", "section_1": "Other Taxes", "section_2": "Net Investment Income Tax", "irs_ref": "Form 8960, line 14, instructions. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[200000.0, 250000.0, 125000.0, 200000.0, 250000.0]], "valid_values": {"min": 0, "max": 9e99}, @@ -4920,18 +4920,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_NIIT_PT_taxed": { + "NIIT_PT_taxed": { "long_name": "Whether or not partnership and S-corp income is in NIIT base", "description": "false ==> partnership and S-corp income excluded from NIIT base; true ==> partnership and S-corp income is in NIIT base.", "section_1": "Other Taxes", "section_2": "Net Investment Income Tax", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -4941,18 +4941,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_NIIT_rt": { + "NIIT_rt": { "long_name": "Net Investment Income Tax rate", "description": "If modified AGI exceeds _NIIT_thd, all net investment income is taxed at this rate.", "section_1": "Other Taxes", "section_2": "Net Investment Income Tax", "irs_ref": "Form 8960, line 21, in-line. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.038], "valid_values": {"min": 0, "max": 1}, @@ -4962,23 +4962,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_c": { + "EITC_c": { "long_name": "Maximum earned income credit", "description": "This is the maximum amount of earned income credit taxpayers are eligible for; it depends on how many kids they have.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, instruction (table).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "EIC", - "col_label": ["0kids", "1kid", "2kids", "3+kids"], + "vi_name": "EIC", + "vi_vals": ["0kids", "1kid", "2kids", "3+kids"], "value_type": "real", "value": [[487.0, 3250.0, 5372.0, 6044.0], [496.0, 3305.0, 5460.0, 6143.0], @@ -4993,18 +4993,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_rt": { + "EITC_rt": { "long_name": "Earned income credit phasein rate", "description": "Pre-phaseout credit is minimum of this rate times earnings and the maximum earned income credit.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, calculation (table: Max_EIC/Max_EIC_base_income).", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "EIC", - "col_label": ["0kids", "1kid", "2kids", "3+kids"], + "vi_name": "EIC", + "vi_vals": ["0kids", "1kid", "2kids", "3+kids"], "value_type": "real", "value": [[0.0765, 0.3400, 0.4000, 0.4500]], "valid_values": {"min": 0, "max": 9e99}, @@ -5014,23 +5014,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_basic_frac": { + "EITC_basic_frac": { "long_name": "Fraction of maximum earned income credit paid at zero earnings", "description": "This fraction of _EITC_c is always paid as a credit and one minus this fraction is applied to the phasein rate, _EITC_rt. This fraction is zero under current law.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, instruction (table).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -5045,18 +5045,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_prt": { + "EITC_prt": { "long_name": "Earned income credit phaseout rate", "description": "Earned income credit begins to decrease at the this rate when AGI is higher than earned income credit phaseout start AGI.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, calculation (table: Max_EIC_base_income/Phaseout_Base).", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "EIC", - "col_label": ["0kids", "1kid", "2kids", "3+kids"], + "vi_name": "EIC", + "vi_vals": ["0kids", "1kid", "2kids", "3+kids"], "value_type": "real", "value": [[0.0765, 0.1598, 0.2106, 0.2106]], "valid_values": {"min": 0, "max": 9e99}, @@ -5066,23 +5066,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_ps": { + "EITC_ps": { "long_name": "Earned income credit phaseout start AGI", "description": "If AGI is higher than this threshold, the amount of EITC will start to decrease at the phaseout rate.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, instructions.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "EIC", - "col_label": ["0kids", "1kid", "2kids", "3+kids"], + "vi_name": "EIC", + "vi_vals": ["0kids", "1kid", "2kids", "3+kids"], "value_type": "real", "value": [[7970.0, 17530.0, 17530.0, 17530.0], [8110.0, 17830.0, 17830.0, 17830.0], @@ -5097,23 +5097,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_ps_MarriedJ": { + "EITC_ps_MarriedJ": { "long_name": "Extra earned income credit phaseout start AGI for married filling jointly", "description": "This is the additional amount added on the regular phaseout start amount for taxpayers with filling status of married filling jointly.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, calculation (the difference between EIC phaseout bases of married jointly fillers and other fillers).", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "EIC", - "col_label": ["0kids", "1kid", "2kids", "3+kids"], + "vi_name": "EIC", + "vi_vals": ["0kids", "1kid", "2kids", "3+kids"], "value_type": "real", "value": [[5340.0, 5340.0, 5340.0, 5340.0], [5430.0, 5430.0, 5430.0, 5430.0], @@ -5128,18 +5128,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_MinEligAge": { + "EITC_MinEligAge": { "long_name": "Minimum Age for Childless EITC Eligibility", "description": "For a childless filling unit, at least one individual's age needs to be no less than this age (but no greater than the EITC_MaxEligAge) in order to be eligible for an earned income tax credit.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, step 4, instructions.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "integer", "value": [25], "valid_values": {"min": 0, "max": 125}, @@ -5149,18 +5149,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_MaxEligAge": { + "EITC_MaxEligAge": { "long_name": "Maximum Age for Childless EITC Eligibility", "description": "For a childless filling unit, at least one individual's age needs to be no greater than this age (but no less than the EITC_MinEligAge) in order to be eligible for an earned income tax credit.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, step 4, instructions.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "integer", "value": [64], "valid_values": {"min": 0, "max": 125}, @@ -5170,23 +5170,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_InvestIncome_c": { + "EITC_InvestIncome_c": { "long_name": "Maximum investment income before EITC reduction", "description": "The EITC amount is reduced when investment income exceeds this ceiling.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, instruction(step2)", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [3300.0, 3350.0, @@ -5201,18 +5201,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_excess_InvestIncome_rt": { + "EITC_excess_InvestIncome_rt": { "long_name": "Rate of EITC reduction when investment income exceeds ceiling", "description": "The EITC amount is reduced at this rate per dollar of investment income exceeding the ceiling.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "Form 1040, line 17, instruction(step2)", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [9e99], "valid_values": {"min": 0, "max": 9e99}, @@ -5222,18 +5222,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_indiv": { + "EITC_indiv": { "long_name": "EITC is computed for each spouse based on individual earnings", - "description": "Current-law value is false implying EITC is filing-unit based; a value of true implies EITC is computed for each individual wage earner. The additional phaseout start for joint filers is not affecected by this parameter, nor are investment income and age eligibilty rules.", + "description": "Current-law value is false implying EITC is filing-unit based; a value of true implies EITC is computed for each individual wage earner. The additional phaseout start for joint filers is not affected by this parameter, nor are investment income and age eligibilty rules.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -5243,18 +5243,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_EITC_sep_filers_elig": { + "EITC_sep_filers_elig": { "long_name": "Separate filers are eligibile for the EITC", "description": "Current-law value is false, implying ineligibility.", "section_1": "Refundable Credits", "section_2": "Earned Income Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -5264,18 +5264,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_LLC_Expense_c": { + "LLC_Expense_c": { "long_name": "Lifetime learning credit expense limit", "description": "The maximum expense eligible for lifetime learning credit, per child.", "section_1": "", "section_2": "", "irs_ref": "Form 8863, line 11, in-line.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [10000.0], "valid_values": {"min": 0, "max": 9e99}, @@ -5285,23 +5285,23 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ETC_pe_Single": { + "ETC_pe_Single": { "long_name": "Education tax credit phaseout ends (Single)", "description": "The education tax credit will be zero for those taxpayers of single filing status with modified AGI (in thousands) higher than this level.", "section_1": "", "section_2": "", "irs_ref": "Form 8863, line 13, inline.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [63.0, 64.0, @@ -5316,23 +5316,23 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ETC_pe_Married": { + "ETC_pe_Married": { "long_name": "Education tax credit phaseout ends (Married)", "description": "The education tax credit will be zero for those taxpayers of married filing status with modified AGI level (in thousands) higher than this level.", "section_1": "", "section_2": "", "irs_ref": "Form 8863, line 13, inline.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [127.0, 128.0, @@ -5347,18 +5347,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_ACTC_rt": { + "ACTC_rt": { "long_name": "Additional Child Tax Credit rate", "description": "This is the fraction of earnings used in calculating the ACTC, which is a partially refundable credit that supplements the CTC for some taxpayers.", "section_1": "Child/Dependent Credits", "section_2": "Additional Child Tax Credit", "irs_ref": "Form 8812, line 8, inline.", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.15], "valid_values": {"min": 0, "max": 1}, @@ -5368,18 +5368,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ACTC_rt_bonus_under5family": { + "ACTC_rt_bonus_under5family": { "long_name": "Bonus additional child tax credit rate for families with qualifying children under 5", "description": "For families with qualifying children under 5 years old, this bonus rate is added to the fraction of earnings (additional child tax credit rate) used in calculating the ACTC.", "section_1": "Child/Dependent Credits", "section_2": "Additional Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5389,31 +5389,31 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ACTC_Income_thd": { + "ACTC_Income_thd": { "long_name": "Additional Child Tax Credit income threshold", "description": "The portion of earned income below this threshold does not count as base for the Additional Child Tax Credit.", "section_1": "Child/Dependent Credits", "section_2": "Additional Child Tax Credit", "irs_ref": "Form 8812, line 7, in-line.", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018", - "2019", - "2020", - "2021", - "2022", - "2023", - "2024", - "2025", - "2026"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018, + 2019, + 2020, + 2021, + 2022, + 2023, + 2024, + 2025, + 2026], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [3000.0, 3000.0, @@ -5436,18 +5436,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_ACTC_ChildNum": { + "ACTC_ChildNum": { "long_name": "Additional Child Tax Credit minimum number of qualified children for different formula", "description": "Families with this number of qualified children or more may qualify for a different formula to calculate the Additional Child Tax Credit, which is a partially refundable credit that supplements the Child Tax Credit for some taxpayers.", "section_1": "Child/Dependent Credits", "section_2": "Additional Child Tax Credit", "irs_ref": "Form 8812, Part II. ", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "integer", "value": [3], "valid_values": {"min": 0, "max": 99}, @@ -5457,18 +5457,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_c": { + "CTC_new_c": { "long_name": "New refundable child tax credit maximum amount per child", "description": "In addition to all credits currently available for dependents, this parameter gives each qualifying child a new refundable credit with this maximum amount.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "Child age qualification for the new child tax credit is the same as under current-law Child Tax Credit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 9e99}, @@ -5478,18 +5478,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_c_under5_bonus": { + "CTC_new_c_under5_bonus": { "long_name": "Bonus new refundable child tax credit maximum for qualifying children under five", "description": "The maximum amount of the new refundable child tax credit allowed for each child is increased by this amount for qualifying children under 5 years old.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": true, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 9e99}, @@ -5499,18 +5499,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_for_all": { + "CTC_new_for_all": { "long_name": "Whether or not maximum amount of the new refundable child tax credit is available to all", "description": "The maximum amount of the new refundable child tax credit does not depend on AGI when true; otherwise, see _CTC_new_rt.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -5520,18 +5520,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_rt": { + "CTC_new_rt": { "long_name": "New refundable child tax credit amount phasein rate", "description": "The maximum amount of the new child tax credit is increased at this rate per dollar of positive AGI until _CTC_new_c times the number of qualified children is reached if CTC_new_for_all is false; if CTC_new_for_all is true, there is no AGI limitation to the maximum amount.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "Child age qualification for the new child tax credit is the same as under current-law Child Tax Credit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 9e99}, @@ -5541,23 +5541,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_ps": { + "CTC_new_ps": { "long_name": "New refundable child tax credit phaseout starting AGI", "description": "The total amount of new child tax credit is reduced for taxpayers with AGI higher than this level.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], @@ -5572,18 +5572,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_prt": { + "CTC_new_prt": { "long_name": "New refundable child tax credit amount phaseout rate", "description": "The total amount of the new child tax credit is reduced at this rate per dollar exceeding the phaseout starting AGI, _CTC_new_ps.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 9e99}, @@ -5593,18 +5593,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_refund_limited": { + "CTC_new_refund_limited": { "long_name": "New child tax credit refund limited to a decimal fraction of payroll taxes", "description": "Specifies whether the new child tax credit refund is limited by the new child tax credit refund limit rate (_CTC_new_refund_limit_payroll_rt).", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "Set this parameter to true to limit the refundability or false to allow full refundability for all taxpayers.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -5614,18 +5614,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_refund_limit_payroll_rt": { + "CTC_new_refund_limit_payroll_rt": { "long_name": "New child tax credit refund limit rate (decimal fraction of payroll taxes)", "description": "The fraction of payroll taxes (employee plus employer shares, but excluding all Medicare payroll taxes) that serves as a limit to the amount of new child tax credit that can be refunded.", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "Set this parameter to zero for no refundability; set it to 9e99 for unlimited refundability for taxpayers with payroll tax liabilities.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 9e99}, @@ -5635,18 +5635,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CTC_new_refund_limited_all_payroll": { + "CTC_new_refund_limited_all_payroll": { "long_name": "New child tax credit refund limit applies to all FICA taxes, not just OASDI", "description": "Specifies whether the new child tax credit refund limit rate (_CTC_new_refund_limit_payroll_rt) applies to all FICA taxes (true) or just OASDI taxes (false).", "section_1": "Refundable Credits", "section_2": "New Refundable Child Tax Credit", "irs_ref": "", "notes": "If the new CTC is limited, set this parameter to true to limit the refundability to all FICA taxes or false to limit refundabiity to OASDI taxes.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -5656,18 +5656,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_FST_AGI_trt": { + "FST_AGI_trt": { "long_name": "New minimum tax; rate as a decimal fraction of AGI", "description": "Individual income taxes and the employee share of payroll taxes are credited against this minimum tax, so the surtax is the difference between the tax rate times AGI and the credited taxes. The new minimum tax is similar to the Fair Share Tax, except that no credits are exempted from the base.", "section_1": "Surtaxes", "section_2": "New Minimum Tax", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5677,23 +5677,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_FST_AGI_thd_lo": { + "FST_AGI_thd_lo": { "long_name": "Minimum AGI needed to be subject to the new minimum tax", "description": "A taxpayer is only subject to the new minimum tax if they exceed this level of AGI.", "section_1": "Surtaxes", "section_2": "New Minimum Tax", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6], [1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6], @@ -5701,30 +5701,30 @@ [1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6], [1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6], [1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6]], - "valid_values": {"min": 0, "max": "_FST_AGI_thd_hi"}, + "valid_values": {"min": 0, "max": "FST_AGI_thd_hi"}, "invalid_minmsg": "", - "invalid_maxmsg": "for _FST_AGI_thd_hi", + "invalid_maxmsg": "for FST_AGI_thd_hi", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_FST_AGI_thd_hi": { + "FST_AGI_thd_hi": { "long_name": "AGI level at which the New Minimum Tax is fully phased in", "description": "The new minimum tax will be fully phased in at this level of AGI. If there is no phase-in, this upper threshold should be set equal to the lower AGI threshold.", "section_1": "Surtaxes", "section_2": "New Minimum Tax", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6], [2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6], @@ -5732,25 +5732,25 @@ [2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6], [2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6], [2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6]], - "valid_values": {"min": "_FST_AGI_thd_lo", "max": 9e99}, - "invalid_minmsg": "for _FST_AGI_thd_lo", + "valid_values": {"min": "FST_AGI_thd_lo", "max": 9e99}, + "invalid_minmsg": "for FST_AGI_thd_lo", "invalid_maxmsg": "", "invalid_action": "stop", "compatible_data": {"puf": true, "cps": true} }, - "_AGI_surtax_trt": { + "AGI_surtax_trt": { "long_name": "New AGI surtax rate", "description": "The surtax rate is applied to the portion of Adjusted Gross Income above the AGI surtax threshold.", "section_1": "Surtaxes", "section_2": "New AGI Surtax", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5760,23 +5760,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_AGI_surtax_thd": { + "AGI_surtax_thd": { "long_name": "Threshold for the new AGI surtax", "description": "The aggregate gross income above this AGI surtax threshold is taxed at surtax rate on AGI.", "section_1": "Surtaxes", "section_2": "New AGI Surtax", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[9e99, 9e99, 9e99, 9e99, 9e99], [9e99, 9e99, 9e99, 9e99, 9e99], @@ -5791,18 +5791,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_LST": { + "LST": { "long_name": "Dollar amount of lump-sum tax", "description": "The lump-sum tax is levied on every member of a tax filing unit. The lump-sum tax is included only in combined taxes; it is not included in income or payroll taxes.", "section_1": "Surtaxes", "section_2": "Lump-Sum Tax", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": -9e99, "max": 9e99}, @@ -5812,23 +5812,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_UBI_u18": { + "UBI_u18": { "long_name": "UBI benefit for those under 18", "description": "UBI benefit provided to people under 18.", "section_1": "Universal Basic Income", "section_2": "UBI Benefits", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -5843,23 +5843,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_UBI_1820": { + "UBI_1820": { "long_name": "UBI benefit for those 18 through 20", "description": "UBI benefit provided to people 18-20 years of age.", "section_1": "Universal Basic Income", "section_2": "UBI Benefits", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -5874,23 +5874,23 @@ "compatible_data": {"puf": true, "cps": true} }, - "_UBI_21": { + "UBI_21": { "long_name": "UBI benefit for those 21 and over", "description": "UBI benefit provided to people 21 and over.", "section_1": "Universal Basic Income", "section_2": "UBI Benefits", "irs_ref": "", "notes": "", - "row_label": ["2013", - "2014", - "2015", - "2016", - "2017", - "2018"], + "value_yrs": [2013, + 2014, + 2015, + 2016, + 2017, + 2018], "indexable": true, "indexed": true, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0, 0.0, @@ -5905,18 +5905,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_UBI_ecrt": { + "UBI_ecrt": { "long_name": "Fraction of UBI benefits excluded from AGI", "description": "One minus this fraction of UBI benefits are taxable and will be added to AGI.", "section_1": "Universal Basic Income", "section_2": "UBI Taxability", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5926,18 +5926,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CR_RetirementSavings_hc": { + "CR_RetirementSavings_hc": { "long_name": "Credit for retirement savings haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the retirement savings credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*RetirementSavingsCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5947,18 +5947,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_ForeignTax_hc": { + "CR_ForeignTax_hc": { "long_name": "Credit for foreign tax haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the foreign tax credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*ForeignTaxCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5968,18 +5968,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_ResidentialEnergy_hc": { + "CR_ResidentialEnergy_hc": { "long_name": "Credit for residential energy haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the residential energy credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*ResidentialEnergyCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -5989,18 +5989,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_GeneralBusiness_hc": { + "CR_GeneralBusiness_hc": { "long_name": "Credit for general business haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the general business credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*GeneralBusinessCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6010,18 +6010,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_MinimumTax_hc": { + "CR_MinimumTax_hc": { "long_name": "Credit for previous year minimum tax credit haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the previous year minimum tax credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*PreviousYearMinimumTaxCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6031,18 +6031,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_AmOppRefundable_hc": { + "CR_AmOppRefundable_hc": { "long_name": "Refundable portion of the American Opportunity Credit haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the refundable American Opportunity credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*RefundablePortionOfAmericanOpportunityCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6052,18 +6052,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_AmOppNonRefundable_hc": { + "CR_AmOppNonRefundable_hc": { "long_name": "Nonrefundable portion of the American Opportunity Credit haircut", "description": "If greater than zero, this decimal fraction reduces the portion of the nonrefundable American Opportunity credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*NonRefundablePortionOfAmericanOpportunityCredit.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6073,18 +6073,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_SchR_hc": { + "CR_SchR_hc": { "long_name": "Schedule R Credit haircut", "description": "If greater than zero, this decimal fraction reduces the portion of Schedule R credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*ScheduleRCredit", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6094,18 +6094,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_OtherCredits_hc": { + "CR_OtherCredits_hc": { "long_name": "Other Credits haircut", "description": "If greater than zero, this decimal fraction reduces the portion of other credit that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*OtherCredits.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6115,18 +6115,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_Education_hc": { + "CR_Education_hc": { "long_name": "Education Credits haircut", "description": "If greater than zero, this decimal fraction reduces the portion of education credits that can be claimed.", "section_1": "Nonrefundable Credits", "section_2": "Misc. Credit Limits", "irs_ref": "", "notes": "Credit claimed will be (1-Haircut)*EducationCredits.", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6136,18 +6136,18 @@ "compatible_data": {"puf": true, "cps": false} }, - "_CR_Charity_rt": { + "CR_Charity_rt": { "long_name": "Charity Credit rate", "description": "If greater than zero, this decimal fraction represents the portion of total charitable contributions provided as a nonrefundable tax credit.", "section_1": "", "section_2": "", "irs_ref": "", "notes": "Credit claimed will be (rt) * (e19800 + e20100)", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6157,18 +6157,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CR_Charity_f": { + "CR_Charity_f": { "long_name": "Charity Credit Floor", "description": "Only charitable giving in excess of this dollar amount is eligible for the charity credit.", "section_1": "", "section_2": "", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "MARS", - "col_label": ["single", "joint", "separate", "headhousehold", "widow"], + "vi_name": "MARS", + "vi_vals": ["single", "mjoint", "marsep", "headhh", "widow"], "value_type": "real", "value": [[0.0, 0.0, 0.0, 0.0, 0.0]], "valid_values": {"min": 0, "max": 9e99}, @@ -6178,18 +6178,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_CR_Charity_frt": { + "CR_Charity_frt": { "long_name": "Charity Credit Floor Rate", "description": "Only charitable giving in excess of this decimal fraction of AGI is eligible for the charity credit.", "section_1": "", "section_2": "", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "real", "value": [0.0], "valid_values": {"min": 0, "max": 1}, @@ -6199,18 +6199,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_BEN_ssi_repeal": { + "BEN_ssi_repeal": { "long_name": "SSI benefit repeal switch", "description": "SSI benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6220,18 +6220,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_housing_repeal": { + "BEN_housing_repeal": { "long_name": "Housing benefit repeal switch", "description": "Housing benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6241,18 +6241,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_snap_repeal": { + "BEN_snap_repeal": { "long_name": "SNAP benefit repeal switch", "description": "SNAP benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6262,18 +6262,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_tanf_repeal": { + "BEN_tanf_repeal": { "long_name": "TANF benefit repeal switch", "description": "TANF benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6283,18 +6283,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_vet_repeal": { + "BEN_vet_repeal": { "long_name": "Veterans benefit repeal switch", "description": "Veterans benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6304,18 +6304,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_wic_repeal": { + "BEN_wic_repeal": { "long_name": "WIC benefit repeal switch", "description": "WIC benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6325,18 +6325,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_mcare_repeal": { + "BEN_mcare_repeal": { "long_name": "Medicare benefit repeal switch", "description": "Medicare benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6346,18 +6346,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_mcaid_repeal": { + "BEN_mcaid_repeal": { "long_name": "Medicaid benefit repeal switch", "description": "Medicaid benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6367,18 +6367,18 @@ "compatible_data": {"puf": false, "cps": true} }, - "_BEN_oasdi_repeal": { + "BEN_oasdi_repeal": { "long_name": "Social Security benefit repeal switch", "description": "Social Security benefits (e02400) can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6388,18 +6388,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_BEN_ui_repeal": { + "BEN_ui_repeal": { "long_name": "Unemployment insurance benefit repeal switch", "description": "Unemployment insurance benefits (e02300) can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, @@ -6409,18 +6409,18 @@ "compatible_data": {"puf": true, "cps": true} }, - "_BEN_other_repeal": { + "BEN_other_repeal": { "long_name": "Other benefit repeal switch", "description": "Other benefits can be repealed by switching this parameter to true.", "section_1": "Benefits", "section_2": "Benefit Repeal", "irs_ref": "", "notes": "", - "row_label": ["2013"], + "value_yrs": [2013], "indexable": false, "indexed": false, - "col_var": "", - "col_label": "", + "vi_name": "", + "vi_vals": [], "value_type": "boolean", "value": [false], "valid_values": {"min": false, "max": true}, diff --git a/taxcalc/reforms/2017_law.json b/taxcalc/reforms/2017_law.json index 16ea71a5e..24e0a293d 100644 --- a/taxcalc/reforms/2017_law.json +++ b/taxcalc/reforms/2017_law.json @@ -13,113 +13,113 @@ // - Set pre-TCJA above the line deduction policy (7) // - Set pre-TCJA itemized deduction policy (8) // Reform_Parameter_Map: -// - 0: _cpi_offset -// - 1: _II_rt?/_II_brk? and _PT_rt?/_PT_brk? -// - 2: four _PT_excl_* parameters -// - 3: _STD and _II_em parameters -// - 4: _CTC_* and _ACTC_* parameters -// - 5: _ODC_c parameter -// - 6: three different _AMT_em* parameters -// - 7: three _ALD_* parameters -// - 8: seven different _ID_* parameters +// - 0: CPI_offset +// - 1: II_rt?/II_brk? and PT_rt?/PT_brk? +// - 2: four PT_excl_* parameters +// - 3: STD and II_em parameters +// - 4: CTC_* and ACTC_* parameters +// - 5: ODC_c parameter +// - 6: three different AMT_em* parameters +// - 7: three ALD_* parameters +// - 8: seven different ID_* parameters // - 9: many parameters not altered by TCJA except for indexing change // NOTE: this reform projects pre-TCJA 2017 parameter values forward using the // unchained CPI-U price index. { "policy": { - "_cpi_offset": {"2017": [0.0025]}, - "_II_rt1": {"2018": [0.10]}, - "_II_brk1": {"2017": [[9325, 18650, 9325, 13350, 18650]]}, - "_II_rt2": {"2018": [0.15]}, - "_II_brk2": {"2017": [[37950, 75900, 37950, 50800, 75900]]}, - "_II_rt3": {"2018": [0.25]}, - "_II_brk3": {"2017": [[91900, 153100, 76550, 131200, 153100]]}, - "_II_rt4": {"2018": [0.28]}, - "_II_brk4": {"2017": [[191650, 233350, 116675, 212500, 233350]]}, - "_II_rt5": {"2018": [0.33]}, - "_II_brk5": {"2017": [[416700, 416700, 208350, 416700, 416700]]}, - "_II_rt6": {"2018": [0.35]}, - "_II_brk6": {"2017": [[418400, 470700, 235350, 444550, 470700]]}, - "_II_rt7": {"2018": [0.396]}, - "_PT_rt1": {"2018": [0.10]}, - "_PT_brk1": {"2017": [[9325, 18650, 9325, 13350, 18650]]}, - "_PT_rt2": {"2018": [0.15]}, - "_PT_brk2": {"2017": [[37950, 75900, 37950, 50800, 75900]]}, - "_PT_rt3": {"2018": [0.25]}, - "_PT_brk3": {"2017": [[91900, 153100, 76550, 131200, 153100]]}, - "_PT_rt4": {"2018": [0.28]}, - "_PT_brk4": {"2017": [[191650, 233350, 116675, 212500, 233350]]}, - "_PT_rt5": {"2018": [0.33]}, - "_PT_brk5": {"2017": [[416700, 416700, 208350, 416700, 416700]]}, - "_PT_rt6": {"2018": [0.35]}, - "_PT_brk6": {"2017": [[418400, 470700, 235350, 444550, 470700]]}, - "_PT_rt7": {"2018": [0.396]}, - "_PT_excl_rt": {"2018": [0]}, - "_PT_excl_wagelim_rt": {"2018": [9e99]}, - "_PT_excl_wagelim_thd": {"2018": [[0, 0, 0, 0, 0]]}, - "_PT_excl_wagelim_prt": {"2018": [[0, 0, 0, 0, 0]]}, - "_STD": {"2017": [[6350, 12700, 6350, 9350, 12700]]}, - "_II_em": {"2017": [4050]}, - "_CTC_c": {"2018": [1000]}, - "_CTC_ps": {"2018": [[75000, 110000, 55000, 75000, 75000]]}, - "_ACTC_c": {"2018": [1000]}, - "_ACTC_Income_thd": {"2018": [3000]}, - "_ODC_c": {"2018": [0]}, - "_AMT_em": {"2017": [[54300, 84500, 42250, 54300, 84500]]}, - "_AMT_em_ps": {"2017": [[120700, 160900, 80450, 120700, 160900]]}, - "_AMT_em_pe": {"2017": [249450]}, - "_ALD_BusinessLosses_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ALD_AlimonyPaid_hc": {"2019": [0]}, - "_ALD_AlimonyReceived_hc": {"2019": [1]}, - "_ALD_DomesticProduction_hc": {"2018": [0]}, - "_ID_prt": {"2018": [0.03]}, - "_ID_crt": {"2018": [0.80]}, - "_ID_Charity_crt_all": {"2018": [0.5]}, - "_ID_Casualty_hc": {"2018": [0]}, - "_ID_AllTaxes_c": {"2018": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_Miscellaneous_hc": {"2018": [0]}, - "_ID_Medical_frt": {"2017": [0.1]}, + "CPI_offset": {"2017": 0.0025}, + "II_rt1": {"2018": 0.10}, + "II_brk1": {"2017": [9325, 18650, 9325, 13350, 18650]}, + "II_rt2": {"2018": 0.15}, + "II_brk2": {"2017": [37950, 75900, 37950, 50800, 75900]}, + "II_rt3": {"2018": 0.25}, + "II_brk3": {"2017": [91900, 153100, 76550, 131200, 153100]}, + "II_rt4": {"2018": 0.28}, + "II_brk4": {"2017": [191650, 233350, 116675, 212500, 233350]}, + "II_rt5": {"2018": 0.33}, + "II_brk5": {"2017": [416700, 416700, 208350, 416700, 416700]}, + "II_rt6": {"2018": 0.35}, + "II_brk6": {"2017": [418400, 470700, 235350, 444550, 470700]}, + "II_rt7": {"2018": 0.396}, + "PT_rt1": {"2018": 0.10}, + "PT_brk1": {"2017": [9325, 18650, 9325, 13350, 18650]}, + "PT_rt2": {"2018": 0.15}, + "PT_brk2": {"2017": [37950, 75900, 37950, 50800, 75900]}, + "PT_rt3": {"2018": 0.25}, + "PT_brk3": {"2017": [91900, 153100, 76550, 131200, 153100]}, + "PT_rt4": {"2018": 0.28}, + "PT_brk4": {"2017": [191650, 233350, 116675, 212500, 233350]}, + "PT_rt5": {"2018": 0.33}, + "PT_brk5": {"2017": [416700, 416700, 208350, 416700, 416700]}, + "PT_rt6": {"2018": 0.35}, + "PT_brk6": {"2017": [418400, 470700, 235350, 444550, 470700]}, + "PT_rt7": {"2018": 0.396}, + "PT_excl_rt": {"2018": 0}, + "PT_excl_wagelim_rt": {"2018": 9e99}, + "PT_excl_wagelim_thd": {"2018": [0, 0, 0, 0, 0]}, + "PT_excl_wagelim_prt": {"2018": [0, 0, 0, 0, 0]}, + "STD": {"2017": [6350, 12700, 6350, 9350, 12700]}, + "II_em": {"2017": 4050}, + "CTC_c": {"2018": 1000}, + "CTC_ps": {"2018": [75000, 110000, 55000, 75000, 75000]}, + "ACTC_c": {"2018": 1000}, + "ACTC_Income_thd": {"2018": 3000}, + "ODC_c": {"2018": 0}, + "AMT_em": {"2017": [54300, 84500, 42250, 54300, 84500]}, + "AMT_em_ps": {"2017": [120700, 160900, 80450, 120700, 160900]}, + "AMT_em_pe": {"2017": 249450}, + "ALD_BusinessLosses_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ALD_AlimonyPaid_hc": {"2019": 0}, + "ALD_AlimonyReceived_hc": {"2019": 1}, + "ALD_DomesticProduction_hc": {"2018": 0}, + "ID_prt": {"2018": 0.03}, + "ID_crt": {"2018": 0.80}, + "ID_Charity_crt_all": {"2018": 0.5}, + "ID_Casualty_hc": {"2018": 0}, + "ID_AllTaxes_c": {"2018": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_Miscellaneous_hc": {"2018": 0}, + "ID_Medical_frt": {"2017": 0.1}, - "_ALD_Dependents_Child_c": {"2017": [0]}, - "_ALD_Dependents_Elder_c": {"2017": [0]}, - "_II_em_ps": {"2017": [[261500, 313800, 156900, 287650, 313800]]}, - "_STD_Dep": {"2017": [1050]}, - "_STD_Aged": {"2017": [[1550, 1250, 1250, 1550, 1550]]}, - "_II_credit": {"2017": [[0, 0, 0, 0, 0]]}, - "_II_credit_ps": {"2017": [[0, 0, 0, 0, 0]]}, - "_II_credit_nr": {"2017": [[0, 0, 0, 0, 0]]}, - "_II_credit_nr_ps": {"2017": [[0, 0, 0, 0, 0]]}, - "_ID_Medical_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_StateLocalTax_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_RealEstate_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_InterestPaid_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_Charity_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_Casualty_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_Miscellaneous_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_ps": {"2017": [[261500, 313800, 156900, 287650, 313800]]}, - "_ID_BenefitSurtax_em": {"2017": [[0, 0, 0, 0, 0]]}, - "_ID_c": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_CG_brk1": {"2017": [[37950, 75900, 37950, 50800, 75900]]}, - "_CG_brk2": {"2017": [[418400, 470700, 235350, 444550, 470700]]}, - "_CG_brk3": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_AMT_CG_brk1": {"2017": [[37950, 75900, 37950, 50800, 75900]]}, - "_AMT_CG_brk2": {"2017": [[418400, 470700, 235350, 444550, 470700]]}, - "_AMT_CG_brk3": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_CG_ec": {"2017": [0]}, - "_AMT_child_em": {"2017": [7500]}, - "_AMT_brk1": {"2017": [187800]}, - "_EITC_c": {"2017": [[510, 3400, 5616, 6318]]}, - "_EITC_ps": {"2017": [[8340, 18340, 18340, 18340]]}, - "_EITC_ps_MarriedJ": {"2017": [[5600, 5600, 5600, 5600]]}, - "_EITC_InvestIncome_c": {"2017": [3450]}, - "_ETC_pe_Single": {"2017": [66]}, - "_ETC_pe_Married": {"2017": [132]}, - "_CTC_new_ps": {"2017": [[0, 0, 0, 0, 0]]}, - "_FST_AGI_thd_lo": {"2017": [[1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6]]}, - "_FST_AGI_thd_hi": {"2017": [[2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6]]}, - "_AGI_surtax_thd": {"2017": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_UBI_u18": {"2017": [0]}, - "_UBI_1820": {"2017": [0]}, - "_UBI_21": {"2017": [0]} + "ALD_Dependents_Child_c": {"2017": 0}, + "ALD_Dependents_Elder_c": {"2017": 0}, + "II_em_ps": {"2017": [261500, 313800, 156900, 287650, 313800]}, + "STD_Dep": {"2017": 1050}, + "STD_Aged": {"2017": [1550, 1250, 1250, 1550, 1550]}, + "II_credit": {"2017": [0, 0, 0, 0, 0]}, + "II_credit_ps": {"2017": [0, 0, 0, 0, 0]}, + "II_credit_nr": {"2017": [0, 0, 0, 0, 0]}, + "II_credit_nr_ps": {"2017": [0, 0, 0, 0, 0]}, + "ID_Medical_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_StateLocalTax_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_RealEstate_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_InterestPaid_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_Charity_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_Casualty_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_Miscellaneous_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_ps": {"2017": [261500, 313800, 156900, 287650, 313800]}, + "ID_BenefitSurtax_em": {"2017": [0, 0, 0, 0, 0]}, + "ID_c": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "CG_brk1": {"2017": [37950, 75900, 37950, 50800, 75900]}, + "CG_brk2": {"2017": [418400, 470700, 235350, 444550, 470700]}, + "CG_brk3": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "AMT_CG_brk1": {"2017": [37950, 75900, 37950, 50800, 75900]}, + "AMT_CG_brk2": {"2017": [418400, 470700, 235350, 444550, 470700]}, + "AMT_CG_brk3": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "CG_ec": {"2017": 0}, + "AMT_child_em": {"2017": 7500}, + "AMT_brk1": {"2017": 187800}, + "EITC_c": {"2017": [510, 3400, 5616, 6318]}, + "EITC_ps": {"2017": [8340, 18340, 18340, 18340]}, + "EITC_ps_MarriedJ": {"2017": [5600, 5600, 5600, 5600]}, + "EITC_InvestIncome_c": {"2017": 3450}, + "ETC_pe_Single": {"2017": 66}, + "ETC_pe_Married": {"2017": 132}, + "CTC_new_ps": {"2017": [0, 0, 0, 0, 0]}, + "FST_AGI_thd_lo": {"2017": [1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6]}, + "FST_AGI_thd_hi": {"2017": [2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6]}, + "AGI_surtax_thd": {"2017": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "UBI_u18": {"2017": 0}, + "UBI_1820": {"2017": 0}, + "UBI_21": {"2017": 0} } } diff --git a/taxcalc/reforms/BrownKhanna.json b/taxcalc/reforms/BrownKhanna.json index 1ed4aa3a5..a29eb410c 100644 --- a/taxcalc/reforms/BrownKhanna.json +++ b/taxcalc/reforms/BrownKhanna.json @@ -9,17 +9,17 @@ // - Increase EITC phase-out start for childless filing units (4) // - Lower EITC minimim eligibility age for childless f.units from 25 to 21 (5) // Reform_Parameter_Map: -// - 1: _EITC_c -// - 2: _EITC_rt -// - 3: _EITC_prt -// - 4: _EITC_ps -// - 5: _EITC_MinEligAge +// - 1: EITC_c +// - 2: EITC_rt +// - 3: EITC_prt +// - 4: EITC_ps +// - 5: EITC_MinEligAge { "policy": { - "_EITC_c": {"2017": [[3000, 6528, 10783, 12131]]}, - "_EITC_rt": {"2017": [[0.3, 0.6258, 0.768, 0.864]]}, - "_EITC_prt": {"2017": [[0.1598, 0.1598, 0.2106, 0.2106]]}, - "_EITC_ps": {"2017": [[18340, 18340, 18340, 18340]]}, - "_EITC_MinEligAge": {"2017": [21]} + "EITC_c": {"2017": [3000, 6528, 10783, 12131]}, + "EITC_rt": {"2017": [0.3, 0.6258, 0.768, 0.864]}, + "EITC_prt": {"2017": [0.1598, 0.1598, 0.2106, 0.2106]}, + "EITC_ps": {"2017": [18340, 18340, 18340, 18340]}, + "EITC_MinEligAge": {"2017": 21} } } diff --git a/taxcalc/reforms/Clinton2016.json b/taxcalc/reforms/Clinton2016.json index 02d82804f..5450aab67 100644 --- a/taxcalc/reforms/Clinton2016.json +++ b/taxcalc/reforms/Clinton2016.json @@ -9,29 +9,29 @@ // - Expansion of the Child Tax Credit and Additional CHild Tax Credit for children under 5 (4) // - Including more business income in the base for the Net Investment Income Tax (5) // Reform_Parameter_Map: -// - 1: _AGI_surtax* -// - 2: _FST_AGI_trt -// - 3: _ID_BenefitCap* +// - 1: AGI_surtax* +// - 2: FST_AGI_trt +// - 3: ID_BenefitCap* // - 4: CTC_c_under5_bonus, ACTC_rt_bonus_under5family // - 5: NIIT_PT_taxed { "policy": { - "_AGI_surtax_trt": - {"2017": [0.04]}, - "_AGI_surtax_thd": - {"2017": [[5.0e6, 5.0e6, 2.5e6, 5.0e6, 5.0e6]]}, - "_FST_AGI_trt": - {"2017": [0.3]}, - "_ID_BenefitCap_Switch": - {"2017": [[true, true, true, true, true, true, false]]}, - "_ID_BenefitCap_rt": - {"2017": [0.28]}, - "_CTC_c_under5_bonus": - {"2017": [1000]}, - "_ACTC_rt_bonus_under5family": - {"2017": [0.3]}, - "_NIIT_PT_taxed": - {"2017": [true]} + "AGI_surtax_trt": + {"2017": 0.04}, + "AGI_surtax_thd": + {"2017": [5.0e6, 5.0e6, 2.5e6, 5.0e6, 5.0e6]}, + "FST_AGI_trt": + {"2017": 0.3}, + "ID_BenefitCap_Switch": + {"2017": [true, true, true, true, true, true, false]}, + "ID_BenefitCap_rt": + {"2017": 0.28}, + "CTC_c_under5_bonus": + {"2017": 1000}, + "ACTC_rt_bonus_under5family": + {"2017": 0.3}, + "NIIT_PT_taxed": + {"2017": true} } } // Note: Due to lack of detail, data, or modeling capability, many provisions cannot be scored. diff --git a/taxcalc/reforms/Larson2019.json b/taxcalc/reforms/Larson2019.json index 3f0563ac1..1873a1baf 100644 --- a/taxcalc/reforms/Larson2019.json +++ b/taxcalc/reforms/Larson2019.json @@ -8,22 +8,22 @@ // - Make wage and self-employment income above $400,000 subject to FICA taxes (2) // - Phase in an increase to the contribution rate starting in 2020 (3) // Reform_Parameter_Map: -// - 1: _SS_thd50, _SS_thd85 -// - 2: _SS_Earnings_thd -// - 3: _FICA_ss_trt +// - 1: SS_thd50, SS_thd85 +// - 2: SS_Earnings_thd +// - 3: FICA_ss_trt { "policy": { - "_SS_thd50": {"2019": [[50000, 100000, 50000, 50000, 50000]]}, - "_SS_thd85": {"2019": [[50000, 100000, 50000, 50000, 50000]]}, - "_SS_Earnings_thd": {"2019": [400000]}, - "_FICA_ss_trt": {"2020": [0.125], - "2021": [0.126], - "2022": [0.127], - "2023": [0.128], - "2024": [0.129], - "2025": [0.130], - "2026": [0.131], - "2027": [0.132], - "2028": [0.133]} + "SS_thd50": {"2019": [50000, 100000, 50000, 50000, 50000]}, + "SS_thd85": {"2019": [50000, 100000, 50000, 50000, 50000]}, + "SS_Earnings_thd": {"2019": 400000}, + "FICA_ss_trt": {"2020": 0.125, + "2021": 0.126, + "2022": 0.127, + "2023": 0.128, + "2024": 0.129, + "2025": 0.130, + "2026": 0.131, + "2027": 0.132, + "2028": 0.133} } } diff --git a/taxcalc/reforms/Renacci.json b/taxcalc/reforms/Renacci.json index b134b3d22..b607a2a18 100644 --- a/taxcalc/reforms/Renacci.json +++ b/taxcalc/reforms/Renacci.json @@ -13,92 +13,92 @@ // - Capital gains and dividends are treated the same as ordinary income (6) // - Increase in EITC (7) // Reform_Parameter_Map: -// -1: _II_rt*,_II_brk* -// -2: _STD -// -3: _II_em -// -4: _ID* -// -5: _AMT_rt* -// -6: _CG_nodiff -// -7: _EITC_c +// -1: II_rt*, II_brk* +// -2: STD +// -3: II_em +// -4: ID* +// -5: AMT_rt* +// -6: CG_nodiff +// -7: EITC_c { "policy":{ - "_II_rt1": { - "2017": [0.1] + "II_rt1": { + "2017": 0.1 }, - "_II_brk1": { - "2017": [[50000,100000,50000,50000,50000]] + "II_brk1": { + "2017": [50000,100000,50000,50000,50000] }, - "_II_rt2": { - "2017": [0.25] + "II_rt2": { + "2017": 0.25 }, - "_II_brk2": { - "2017": [[750000,1500000,750000,750000,750000]] + "II_brk2": { + "2017": [750000,1500000,750000,750000,750000] }, - "_II_rt3": { - "2017": [0.35] + "II_rt3": { + "2017": 0.35 }, - "_II_brk3": { - "2017": [[9e99,9e99,9e99,9e99,9e99]] + "II_brk3": { + "2017": [9e99,9e99,9e99,9e99,9e99] }, - "_II_rt4": { - "2017": [0.35] + "II_rt4": { + "2017": 0.35 }, - "_II_brk4": { - "2017": [[9e99,9e99,9e99,9e99,9e99]] + "II_brk4": { + "2017": [9e99,9e99,9e99,9e99,9e99] }, - "_II_rt5": { - "2017": [0.35] + "II_rt5": { + "2017": 0.35 }, - "_II_brk5": { - "2017": [[9e99,9e99,9e99,9e99,9e99]] + "II_brk5": { + "2017": [9e99,9e99,9e99,9e99,9e99] }, - "_II_rt6": { - "2017": [0.35] + "II_rt6": { + "2017": 0.35 }, - "_II_brk6": { - "2017": [[9e99,9e99,9e99,9e99,9e99]] + "II_brk6": { + "2017": [9e99,9e99,9e99,9e99,9e99] }, - "_II_rt7": { - "2017": [0.35] + "II_rt7": { + "2017": 0.35 }, - "_II_brk7": { - "2017": [[9e99,9e99,9e99,9e99,9e99]] + "II_brk7": { + "2017": [9e99,9e99,9e99,9e99,9e99] }, - "_STD": { - "2017": [[15000,30000,15000,15000,15000]] + "STD": { + "2017": [15000,30000,15000,15000,15000] }, - "_II_em": { - "2017": [5000] + "II_em": { + "2017": 5000 }, - "_ID_StateLocalTax_hc": { - "2017": [1] + "ID_StateLocalTax_hc": { + "2017": 1 }, - "_ID_Medical_hc": { - "2017": [1] + "ID_Medical_hc": { + "2017": 1 }, - "_ID_Casualty_hc": { - "2017": [1] + "ID_Casualty_hc": { + "2017": 1 }, - "_ID_Miscellaneous_hc": { - "2017": [1] + "ID_Miscellaneous_hc": { + "2017": 1 }, - "_ID_RealEstate_hc": { - "2017": [1] + "ID_RealEstate_hc": { + "2017": 1 }, - "_ID_InterestPaid_c": { - "2017": [[19730.0, 19730.0, 19730.0, 19730.0, 19730.0]] + "ID_InterestPaid_c": { + "2017": [19730.0, 19730.0, 19730.0, 19730.0, 19730.0] }, - "_AMT_rt1": { - "2017": [0] + "AMT_rt1": { + "2017": 0 }, - "_AMT_rt2": { - "2017": [0] + "AMT_rt2": { + "2017": 0 }, - "_CG_nodiff": { - "2017": [true] + "CG_nodiff": { + "2017": true }, - "_EITC_c": { - "2017": [[1020, 4760, 7862, 8845]] + "EITC_c": { + "2017": [1020, 4760, 7862, 8845] } } } diff --git a/taxcalc/reforms/SandersDeFazio.json b/taxcalc/reforms/SandersDeFazio.json index c23395b58..aaddee825 100644 --- a/taxcalc/reforms/SandersDeFazio.json +++ b/taxcalc/reforms/SandersDeFazio.json @@ -7,11 +7,11 @@ // - Apply the combined OASDI payroll tax rate on earnings above $250,000, effective 2020 (1) // - Apply a separate 6.2 percent tax on investment income above ACA threshold (2) // Reform_Parameter_Map: -// - 1: _SS_Earnings_thd -// - 2: _NIIT_rt +// - 1: SS_Earnings_thd +// - 2: NIIT_rt { "policy": { - "_SS_Earnings_thd": {"2020": [250000]}, - "_NIIT_rt": {"2020": [0.100]} + "SS_Earnings_thd": {"2020": 250000}, + "NIIT_rt": {"2020": 0.100} } } diff --git a/taxcalc/reforms/TCJA.json b/taxcalc/reforms/TCJA.json index 94c4fec74..23a411439 100644 --- a/taxcalc/reforms/TCJA.json +++ b/taxcalc/reforms/TCJA.json @@ -14,177 +14,177 @@ // - Changes to itemized deductions (8) // - Switch to chained CPI from CPI-U for tax parameter adjustment (9) // Reform_Parameter_Map: -// - 1: _II_* -// - 2: _PT_* -// - 3: _STD (can safely ignore WARNINGs about 2026+ values) -// - 4: _II_em -// - 5: _ODC_c, _CTC_c, _CTC_ps, _ACTC_c, _ACTC_Income_thd -// - 6: _AMT_em* -// - 7: _ALD_* -// - 8: _ID_* (can safely ignore WARNINGs about values for several parameters) -// - 9: _cpi_offset -// Note: _II_brk*, _PT_brk*, _STD, _II_em are rounded to nearest integer value +// - 1: II_* +// - 2: PT_* +// - 3: STD (can safely ignore WARNINGs about 2026+ values) +// - 4: II_em +// - 5: ODC_c, _CTC_c, _CTC_ps, _ACTC_c, _ACTC_Income_thd +// - 6: AMT_em* +// - 7: ALD_* +// - 8: ID_* (can safely ignore WARNINGs about values for several parameters) +// - 9: CPI_offset +// Note: II_brk*, PT_brk*, STD, II_em are rounded to nearest integer value { "policy": { - "_II_rt1": - {"2018": [0.10], - "2026": [0.10]}, - "_II_rt2": - {"2018": [0.12], - "2026": [0.15]}, - "_II_rt3": - {"2018": [0.22], - "2026": [0.25]}, - "_II_rt4": - {"2018": [0.24], - "2026": [0.28]}, - "_II_rt5": - {"2018": [0.32], - "2026": [0.33]}, - "_II_rt6": - {"2018": [0.35], - "2026": [0.35]}, - "_II_rt7": - {"2018": [0.37], - "2026": [0.396]}, - "_II_brk1": - {"2018": [[9525, 19050, 9525, 13600, 19050]], - "2026": [[11242, 22484, 11242, 16094, 22484]]}, - "_II_brk2": - {"2018": [[38700, 77400, 38700, 51800, 77400]], - "2026": [[45751, 91502, 45751, 61242, 91502]]}, - "_II_brk3": - {"2018": [[82500, 165000, 82500, 82500, 165000]], - "2026": [[110791, 184571, 92286, 158169, 184571]]}, - "_II_brk4": - {"2018": [[157500, 315000, 157500, 157500, 315000]], - "2026": [[231045, 281317, 140659, 256181, 281317]]}, - "_II_brk5": - {"2018": [[200000, 400000, 200000, 200000, 400000]], - "2026": [[502356, 502356, 251178, 502356, 502356]]}, - "_II_brk6": - {"2018": [[500000, 600000, 300000, 500000, 600000]], - "2026": [[504406 ,567457, 283728, 535931, 567457]]}, - "_PT_rt1": - {"2018": [0.10], - "2026": [0.10]}, - "_PT_rt2": - {"2018": [0.12], - "2026": [0.15]}, - "_PT_rt3": - {"2018": [0.22], - "2026": [0.25]}, - "_PT_rt4": - {"2018": [0.24], - "2026": [0.28]}, - "_PT_rt5": - {"2018": [0.32], - "2026": [0.33]}, - "_PT_rt6": - {"2018": [0.35], - "2026": [0.35]}, - "_PT_rt7": - {"2018": [0.37], - "2026": [0.396]}, - "_PT_brk1": - {"2018": [[9525, 19050, 9525, 13600, 19050]], - "2026": [[11242, 22484, 11242, 16094, 22484]]}, - "_PT_brk2": - {"2018": [[38700, 77400, 38700, 51800, 77400]], - "2026": [[45751, 91502, 45751, 61242, 91502]]}, - "_PT_brk3": - {"2018": [[82500, 165000, 82500, 82500, 165000]], - "2026": [[110791, 184571, 92286, 158169, 184571]]}, - "_PT_brk4": - {"2018": [[157500, 315000, 157500, 157500, 315000]], - "2026": [[231045, 281317, 140659, 256181, 281317]]}, - "_PT_brk5": - {"2018": [[200000, 400000, 200000, 200000, 400000]], - "2026": [[502356, 502356, 251178, 502356, 502356]]}, - "_PT_brk6": - {"2018": [[500000, 600000, 300000, 500000, 600000]], - "2026": [[504406, 567457, 283728, 535931, 567457]]}, - "_PT_excl_rt": - {"2018": [0.2], - "2026": [0.0]}, - "_PT_excl_wagelim_rt": - {"2018": [0.5], - "2026": [9e99]}, - "_PT_excl_wagelim_thd": - {"2018": [[157500, 315000, 157500, 157500, 315000]], - "2026": [[0, 0, 0, 0, 0]]}, - "_PT_excl_wagelim_prt": - {"2018": [[0.00002, 0.00001, 0.00002, 0.00002, 0.00001]], - "2026": [[0, 0, 0, 0, 0]]}, - "_STD": - {"2018": [[12000, 24000, 12000, 18000, 24000]], - "2026": [[7655, 15311, 7655, 11272, 15311]]}, - "_II_em": - {"2018": [0], - "2026": [4883]}, - "_ODC_c": - {"2018": [500], - "2026": [0]}, - "_CTC_c": - {"2018": [2000], - "2026": [1000]}, - "_CTC_ps": - {"2018": [[200000, 400000, 200000, 200000, 400000]], - "2026": [[75000, 110000, 55000, 75000, 75000]]}, - "_ACTC_c": - {"2018": [1400], - "2022": [1500], - "2025": [1600], - "2026": [1000]}, - "_ACTC_Income_thd": - {"2018": [2500], - "2026": [3000]}, - "_AMT_em": - {"2018": [[70300, 109400, 54700, 70300, 109400]], - "2026": [[65462, 101870, 50935, 65461, 101870]]}, - "_AMT_em_ps": - {"2018": [[500000, 1000000, 500000, 500000, 1000000]], - "2026": [[145511, 193974, 96987, 145511, 193974]]}, - "_AMT_em_pe": - {"2018": [718800], - "2026": [302083]}, - "_ALD_DomesticProduction_hc": - {"2018": [1], - "2026": [0]}, - "_ALD_AlimonyPaid_hc": - {"2019": [1], - "2026": [0]}, - "_ALD_AlimonyReceived_hc": - {"2019": [0], - "2026": [1]}, - "_ALD_BusinessLosses_c": - {"2018": [[250000, 500000, 250000, 250000, 500000]], - "2026": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_ps": - {"2018": [[9e99, 9e99, 9e99, 9e99, 9e99]], - "2026": [[316675, 380010, 190005, 348343, 380010]]}, - "_ID_prt": - {"2018": [0.00], - "2026": [0.03]}, - "_ID_crt": - {"2018": [1.0], - "2026": [0.8]}, - "_ID_Charity_crt_all": - {"2018": [0.6], - "2026": [0.5]}, - "_ID_Casualty_hc": - {"2018": [1], - "2026": [0]}, - "_ID_AllTaxes_c": - {"2018": [[10000, 10000, 5000, 10000, 10000]], - "2026": [[9e99, 9e99, 9e99, 9e99, 9e99]]}, - "_ID_Miscellaneous_hc": - {"2018": [1], - "2026": [0]}, - "_ID_Medical_frt": - {"2017": [0.075], - "2019": [0.100]}, - "_cpi_offset": - {"2017": [-0.0025]} + "II_rt1": + {"2018": 0.10, + "2026": 0.10}, + "II_rt2": + {"2018": 0.12, + "2026": 0.15}, + "II_rt3": + {"2018": 0.22, + "2026": 0.25}, + "II_rt4": + {"2018": 0.24, + "2026": 0.28}, + "II_rt5": + {"2018": 0.32, + "2026": 0.33}, + "II_rt6": + {"2018": 0.35, + "2026": 0.35}, + "II_rt7": + {"2018": 0.37, + "2026": 0.396}, + "II_brk1": + {"2018": [9525, 19050, 9525, 13600, 19050], + "2026": [11242, 22484, 11242, 16094, 22484]}, + "II_brk2": + {"2018": [38700, 77400, 38700, 51800, 77400], + "2026": [45751, 91502, 45751, 61242, 91502]}, + "II_brk3": + {"2018": [82500, 165000, 82500, 82500, 165000], + "2026": [110791, 184571, 92286, 158169, 184571]}, + "II_brk4": + {"2018": [157500, 315000, 157500, 157500, 315000], + "2026": [231045, 281317, 140659, 256181, 281317]}, + "II_brk5": + {"2018": [200000, 400000, 200000, 200000, 400000], + "2026": [502356, 502356, 251178, 502356, 502356]}, + "II_brk6": + {"2018": [500000, 600000, 300000, 500000, 600000], + "2026": [504406 ,567457, 283728, 535931, 567457]}, + "PT_rt1": + {"2018": 0.10, + "2026": 0.10}, + "PT_rt2": + {"2018": 0.12, + "2026": 0.15}, + "PT_rt3": + {"2018": 0.22, + "2026": 0.25}, + "PT_rt4": + {"2018": 0.24, + "2026": 0.28}, + "PT_rt5": + {"2018": 0.32, + "2026": 0.33}, + "PT_rt6": + {"2018": 0.35, + "2026": 0.35}, + "PT_rt7": + {"2018": 0.37, + "2026": 0.396}, + "PT_brk1": + {"2018": [9525, 19050, 9525, 13600, 19050], + "2026": [11242, 22484, 11242, 16094, 22484]}, + "PT_brk2": + {"2018": [38700, 77400, 38700, 51800, 77400], + "2026": [45751, 91502, 45751, 61242, 91502]}, + "PT_brk3": + {"2018": [82500, 165000, 82500, 82500, 165000], + "2026": [110791, 184571, 92286, 158169, 184571]}, + "PT_brk4": + {"2018": [157500, 315000, 157500, 157500, 315000], + "2026": [231045, 281317, 140659, 256181, 281317]}, + "PT_brk5": + {"2018": [200000, 400000, 200000, 200000, 400000], + "2026": [502356, 502356, 251178, 502356, 502356]}, + "PT_brk6": + {"2018": [500000, 600000, 300000, 500000, 600000], + "2026": [504406, 567457, 283728, 535931, 567457]}, + "PT_excl_rt": + {"2018": 0.2, + "2026": 0.0}, + "PT_excl_wagelim_rt": + {"2018": 0.5, + "2026": 9e99}, + "PT_excl_wagelim_thd": + {"2018": [157500, 315000, 157500, 157500, 315000], + "2026": [0, 0, 0, 0, 0]}, + "PT_excl_wagelim_prt": + {"2018": [0.00002, 0.00001, 0.00002, 0.00002, 0.00001], + "2026": [0, 0, 0, 0, 0]}, + "STD": + {"2018": [12000, 24000, 12000, 18000, 24000], + "2026": [7655, 15311, 7655, 11272, 15311]}, + "II_em": + {"2018": 0, + "2026": 4883}, + "ODC_c": + {"2018": 500, + "2026": 0}, + "CTC_c": + {"2018": 2000, + "2026": 1000}, + "CTC_ps": + {"2018": [200000, 400000, 200000, 200000, 400000], + "2026": [75000, 110000, 55000, 75000, 75000]}, + "ACTC_c": + {"2018": 1400, + "2022": 1500, + "2025": 1600, + "2026": 1000}, + "ACTC_Income_thd": + {"2018": 2500, + "2026": 3000}, + "AMT_em": + {"2018": [70300, 109400, 54700, 70300, 109400], + "2026": [65462, 101870, 50935, 65461, 101870]}, + "AMT_em_ps": + {"2018": [500000, 1000000, 500000, 500000, 1000000], + "2026": [145511, 193974, 96987, 145511, 193974]}, + "AMT_em_pe": + {"2018": 718800, + "2026": 302083}, + "ALD_DomesticProduction_hc": + {"2018": 1, + "2026": 0}, + "ALD_AlimonyPaid_hc": + {"2019": 1, + "2026": 0}, + "ALD_AlimonyReceived_hc": + {"2019": 0, + "2026": 1}, + "ALD_BusinessLosses_c": + {"2018": [250000, 500000, 250000, 250000, 500000], + "2026": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_ps": + {"2018": [9e99, 9e99, 9e99, 9e99, 9e99], + "2026": [316675, 380010, 190005, 348343, 380010]}, + "ID_prt": + {"2018": 0.00, + "2026": 0.03}, + "ID_crt": + {"2018": 1.0, + "2026": 0.8}, + "ID_Charity_crt_all": + {"2018": 0.6, + "2026": 0.5}, + "ID_Casualty_hc": + {"2018": 1, + "2026": 0}, + "ID_AllTaxes_c": + {"2018": [10000, 10000, 5000, 10000, 10000], + "2026": [9e99, 9e99, 9e99, 9e99, 9e99]}, + "ID_Miscellaneous_hc": + {"2018": 1, + "2026": 0}, + "ID_Medical_frt": + {"2017": 0.075, + "2019": 0.100}, + "CPI_offset": + {"2017": -0.0025} } } diff --git a/taxcalc/reforms/Trump2016.json b/taxcalc/reforms/Trump2016.json index 8f2cf1acb..b5587e990 100644 --- a/taxcalc/reforms/Trump2016.json +++ b/taxcalc/reforms/Trump2016.json @@ -13,91 +13,91 @@ // - New above the line deduction for child and elder care (8) // - Cap itemized deductions (9) // Reform_Parameter_Map: -// - 1: _II_rt*, II_brk* -// - 2: _PT_* -// - 3: _CG_* -// - 4: _AMT_* -// - 5: _NIIT_rt -// - 6: _STD -// - 7: _II_em -// - 8: _ALD_Dependents* -// - 9: _ID_c +// - 1: II_rt*, II_brk* +// - 2: PT_* +// - 3: CG_* +// - 4: AMT_* +// - 5: NIIT_rt +// - 6: STD +// - 7: II_em +// - 8: ALD_Dependents* +// - 9: ID_c { "policy": { - "_II_rt1": - {"2017": [0.12]}, - "_II_brk1": - {"2017": [[37500, 75000, 37500, 37500, 75000]]}, - "_II_rt2": - {"2017": [0.25]}, - "_II_brk2": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_II_rt3": - {"2017": [0.25]}, - "_II_brk3": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_II_rt4": - {"2017": [0.25]}, - "_II_brk4": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_II_rt5": - {"2017": [0.25]}, - "_II_brk5": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_II_rt6": - {"2017": [0.25]}, - "_II_brk6": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_II_rt7": - {"2017": [0.33]}, - "_PT_rt1": - {"2017": [0.12]}, - "_PT_brk1": - {"2017": [[37500, 75000, 37500, 37500, 75000]]}, - "_PT_rt2": - {"2017": [0.15]}, - "_PT_brk2": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_PT_rt3": - {"2017": [0.15]}, - "_PT_brk3": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_PT_rt4": - {"2017": [0.15]}, - "_PT_brk4": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_PT_rt5": - {"2017": [0.15]}, - "_PT_brk5": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_PT_rt6": - {"2017": [0.15]}, - "_PT_brk6": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_PT_rt7": - {"2017": [0.15]}, - "_CG_brk1": - {"2017": [[37500, 75000, 37500, 37500, 75000]]}, - "_CG_brk2": - {"2017": [[112500, 225000, 112500, 112500, 225000]]}, - "_AMT_rt1": - {"2017": [0]}, - "_AMT_rt2": - {"2017": [0]}, - "_NIIT_rt": - {"2017": [0]}, - "_STD": - {"2017": [[15000, 30000, 15000, 15000, 30000]]}, - "_II_em": - {"2017": [0]}, - "_ALD_Dependents_thd": - {"2017": [[250000, 500000, 250000, 500000, 500000]]}, - "_ALD_Dependents_Elder_c": - {"2017": [5000]}, - "_ALD_Dependents_Child_c": - {"2017": [7156]}, - "_ID_c": - {"2017": [[100000, 200000, 100000, 100000, 200000]]} + "II_rt1": + {"2017": 0.12}, + "II_brk1": + {"2017": [37500, 75000, 37500, 37500, 75000]}, + "II_rt2": + {"2017": 0.25}, + "II_brk2": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "II_rt3": + {"2017": 0.25}, + "II_brk3": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "II_rt4": + {"2017": 0.25}, + "II_brk4": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "II_rt5": + {"2017": 0.25}, + "II_brk5": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "II_rt6": + {"2017": 0.25}, + "II_brk6": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "II_rt7": + {"2017": 0.33}, + "PT_rt1": + {"2017": 0.12}, + "PT_brk1": + {"2017": [37500, 75000, 37500, 37500, 75000]}, + "PT_rt2": + {"2017": 0.15}, + "PT_brk2": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "PT_rt3": + {"2017": 0.15}, + "PT_brk3": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "PT_rt4": + {"2017": 0.15}, + "PT_brk4": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "PT_rt5": + {"2017": 0.15}, + "PT_brk5": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "PT_rt6": + {"2017": 0.15}, + "PT_brk6": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "PT_rt7": + {"2017": 0.15}, + "CG_brk1": + {"2017": [37500, 75000, 37500, 37500, 75000]}, + "CG_brk2": + {"2017": [112500, 225000, 112500, 112500, 225000]}, + "AMT_rt1": + {"2017": 0}, + "AMT_rt2": + {"2017": 0}, + "NIIT_rt": + {"2017": 0}, + "STD": + {"2017": [15000, 30000, 15000, 15000, 30000]}, + "II_em": + {"2017": 0}, + "ALD_Dependents_thd": + {"2017": [250000, 500000, 250000, 500000, 500000]}, + "ALD_Dependents_Elder_c": + {"2017": 5000}, + "ALD_Dependents_Child_c": + {"2017": 7156}, + "ID_c": + {"2017": [100000, 200000, 100000, 100000, 200000]} } } diff --git a/taxcalc/reforms/Trump2017.json b/taxcalc/reforms/Trump2017.json index ea45700d8..3c0c77e04 100644 --- a/taxcalc/reforms/Trump2017.json +++ b/taxcalc/reforms/Trump2017.json @@ -10,60 +10,60 @@ // - Double the Standard Deduction (5) // - Eliminate all itemized deductions except mortgage interest and charitable contributions (6) // Reform_Parameter_Map: -// - 1: _II_rt* -// - 2: _PT_* -// - 3: _AMT_* -// - 4: _NIIT_rt -// - 5: _STD -// - 6: _ID_* +// - 1: II_rt* +// - 2: PT_* +// - 3: AMT_* +// - 4: NIIT_rt +// - 5: STD +// - 6: ID_* { "policy": { - "_II_rt1": - {"2017": [0.10]}, - "_II_rt2": - {"2017": [0.10]}, - "_II_rt3": - {"2017": [0.25]}, - "_II_rt4": - {"2017": [0.25]}, - "_II_rt5": - {"2017": [0.25]}, - "_II_rt6": - {"2017": [0.35]}, - "_II_rt7": - {"2017": [0.35]}, - "_PT_rt1": - {"2017": [0.1]}, - "_PT_rt2": - {"2017": [0.1]}, - "_PT_rt3": - {"2017": [0.15]}, - "_PT_rt4": - {"2017": [0.15]}, - "_PT_rt5": - {"2017": [0.15]}, - "_PT_rt6": - {"2017": [0.15]}, - "_PT_rt7": - {"2017": [0.15]}, - "_AMT_rt1": - {"2017": [0]}, - "_AMT_rt2": - {"2017": [0]}, - "_NIIT_rt": - {"2017": [0]}, - "_STD": - {"2017": [[12700, 25400, 12700, 18700, 25400]]}, - "_ID_StateLocalTax_hc": - {"2017": [1.0]}, - "_ID_Medical_hc": - {"2017": [1.0]}, - "_ID_Casualty_hc": - {"2017": [1.0]}, - "_ID_Miscellaneous_hc": - {"2017": [1.0]}, - "_ID_RealEstate_hc": - {"2017": [1.0]} + "II_rt1": + {"2017": 0.10}, + "II_rt2": + {"2017": 0.10}, + "II_rt3": + {"2017": 0.25}, + "II_rt4": + {"2017": 0.25}, + "II_rt5": + {"2017": 0.25}, + "II_rt6": + {"2017": 0.35}, + "II_rt7": + {"2017": 0.35}, + "PT_rt1": + {"2017": 0.1}, + "PT_rt2": + {"2017": 0.1}, + "PT_rt3": + {"2017": 0.15}, + "PT_rt4": + {"2017": 0.15}, + "PT_rt5": + {"2017": 0.15}, + "PT_rt6": + {"2017": 0.15}, + "PT_rt7": + {"2017": 0.15}, + "AMT_rt1": + {"2017": 0}, + "AMT_rt2": + {"2017": 0}, + "NIIT_rt": + {"2017": 0}, + "STD": + {"2017": [12700, 25400, 12700, 18700, 25400]}, + "ID_StateLocalTax_hc": + {"2017": 1.0}, + "ID_Medical_hc": + {"2017": 1.0}, + "ID_Casualty_hc": + {"2017": 1.0}, + "ID_Miscellaneous_hc": + {"2017": 1.0}, + "ID_RealEstate_hc": + {"2017": 1.0} } } diff --git a/taxcalc/reforms/ptaxes0.json b/taxcalc/reforms/ptaxes0.json index 0be5781fa..bc316139d 100644 --- a/taxcalc/reforms/ptaxes0.json +++ b/taxcalc/reforms/ptaxes0.json @@ -6,8 +6,8 @@ // - raise OASDI payroll tax rate in 2018 and 2020 (1) // - raise HI payroll tax rate in 2019 and 2021 (2) // Reform_Parameter_Map: -// - 1: _FICA_ss_trt -// - 2: _FICA_mc_trt +// - 1: FICA_ss_trt +// - 2: FICA_mc_trt // NOTE: this reform produces the following rates by year: // 2017: 0.124 0.029 // 2018: 0.130 0.029 @@ -17,13 +17,13 @@ // 2022: 0.140 0.032 { "policy": { - "_FICA_ss_trt": { - "2018": [0.130], - "2020": [0.140] + "FICA_ss_trt": { + "2018": 0.130, + "2020": 0.140 }, - "_FICA_mc_trt": { - "2019": [0.030], - "2021": [0.032] + "FICA_mc_trt": { + "2019": 0.030, + "2021": 0.032 } } } diff --git a/taxcalc/reforms/ptaxes1.json b/taxcalc/reforms/ptaxes1.json index 109d476df..a8a3f72a3 100644 --- a/taxcalc/reforms/ptaxes1.json +++ b/taxcalc/reforms/ptaxes1.json @@ -5,7 +5,7 @@ // - raise MTE to 200,000 in 2018 and wage index after that and then // raise MTE to 250,000 in 2020 and wage index after that (1) // Reform_Parameter_Map: -// - 1: _SS_Earnings_c +// - 1: SS_Earnings_c // NOTE: this reform produces the following MTE by year: // 2017: 127200 // 2018: 200000 @@ -14,9 +14,9 @@ // 2021: wage-indexed 250000 { "policy": { - "_SS_Earnings_c": { - "2018": [200000], - "2020": [250000] + "SS_Earnings_c": { + "2018": 200000, + "2020": 250000 } } } diff --git a/taxcalc/reforms/ptaxes2.json b/taxcalc/reforms/ptaxes2.json index 819b4dbda..4a14f6617 100644 --- a/taxcalc/reforms/ptaxes2.json +++ b/taxcalc/reforms/ptaxes2.json @@ -4,7 +4,7 @@ // Reform_Description: // - raise MTE to essentially infinity in 2020 and wage index after that // Reform_Parameter_Map: -// - 1: _SS_Earnings_c +// - 1: SS_Earnings_c // NOTE: this reform produces the following MTE by year: // 2017: 127200 // 2018: wage-indexed 127200 @@ -13,8 +13,8 @@ // 2021: wage-indexed 9e99 (an even bigger MTE value) { "policy": { - "_SS_Earnings_c": { - "2020": [9e99] + "SS_Earnings_c": { + "2020": 9e99 } } } diff --git a/taxcalc/reforms/ptaxes3.json b/taxcalc/reforms/ptaxes3.json index 1a14c3644..773f27282 100644 --- a/taxcalc/reforms/ptaxes3.json +++ b/taxcalc/reforms/ptaxes3.json @@ -8,22 +8,22 @@ // - raise AddMedTax earnings exclusion in 2019 (2) // - begin price indexing AddMedTax earnings exclusion in years after 2019 (3) // Reform_Parameter_Map: -// - 1: _AMEDT_rt -// - 2: _AMEDT_ec -// - 3: _AMEDT_ec_cpi +// - 1: AMEDT_rt +// - 2: AMEDT_ec +// - 3: AMEDT_ec-indexed // NOTE: this reform produces the following parameter values by year: // 2018: 0.009 200000 250000 125000 200000 200000 // 2019: 0.010 250000 300000 150000 250000 250000 // 2020: 0.010 ...... price indexed 2019 values ..... { "policy": { - "_AMEDT_rt": { - "2019": [0.010] + "AMEDT_rt": { + "2019": 0.010 }, - "_AMEDT_ec": { - "2019": [[250000, 300000, 150000, 250000, 250000]] + "AMEDT_ec": { + "2019": [250000, 300000, 150000, 250000, 250000] }, - "_AMEDT_ec_cpi": { + "AMEDT_ec-indexed": { "2019": true } } diff --git a/taxcalc/tests/reforms.json b/taxcalc/tests/reforms.json index c73729e1f..7746c33aa 100644 --- a/taxcalc/tests/reforms.json +++ b/taxcalc/tests/reforms.json @@ -2,7 +2,7 @@ "1": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_FICA_ss_trt": [0.134]}, + "value": {"FICA_ss_trt": 0.134}, "name": "Increase OASDI payroll tax rate by 1 pts", "output_type": "payrolltax", "compare_with": {} @@ -11,7 +11,7 @@ "2": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_SS_Earnings_c": [177500]}, + "value": {"SS_Earnings_c": 177500}, "name": "Increase OASDI maximum taxable earnings to $177,500", "output_type": "payrolltax", "compare_with": {"Budget Options": [40, 46, 49, 51]} @@ -20,7 +20,7 @@ "3": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_FICA_mc_trt": [0.039]}, + "value": {"FICA_mc_trt": 0.039}, "name": "Increase HI payroll tax rate by 1 pts", "output_type": "payrolltax", "compare_with": {"Budget Options": [73, 77, 82, 87]} @@ -29,7 +29,7 @@ "4": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMEDT_ec": [[210000, 260000, 135000, 210000, 210000]]}, + "value": {"AMEDT_ec": [210000, 260000, 135000, 210000, 210000]}, "name": "Increase Additional Medicare Tax exclusion by $10,000", "output_type": "payrolltax", "compare_with": {} @@ -38,7 +38,7 @@ "5": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMEDT_rt": [0.01]}, + "value": {"AMEDT_rt": 0.01}, "name": "Increase Additional Medicare Tax rate by 0.1 pts", "output_type": "payrolltax", "compare_with": {} @@ -47,10 +47,10 @@ "6": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_SS_thd50": [[0, 0, 0, 0, 0]], - "_SS_thd85": [[0, 0, 0, 0, 0]], - "_SS_percentage1": [1], - "_SS_percentage2": [1]}, + "value": {"SS_thd50": [0, 0, 0, 0, 0], + "SS_thd85": [0, 0, 0, 0, 0], + "SS_percentage1": 1, + "SS_percentage2": 1}, "name": "All OASDI benefits included in AGI", "output_type": "iitax", "compare_with": {"Tax Expenditure": [39.3, 41.5, 44.1, 46.8], @@ -60,7 +60,7 @@ "7": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ALD_KEOGH_SEP_hc": [1]}, + "value": {"ALD_KEOGH_SEP_hc": 1}, "name": "No deduction for KEOGH/SEP contributions", "output_type": "iitax", "compare_with": {"Tax Expenditure": [8.7, 10.0, 11.4, 16.2]} @@ -69,7 +69,7 @@ "8": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ALD_StudentLoan_hc": [1]}, + "value": {"ALD_StudentLoan_hc": 1}, "name": "No deduction for student-loan interest", "output_type": "iitax", "compare_with": {"Tax Expenditure": [1.8, 1.9, 1.9, 2.1]} @@ -78,7 +78,7 @@ "9": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ALD_SelfEmploymentTax_hc": [1]}, + "value": {"ALD_SelfEmploymentTax_hc": 1}, "name": "Eliminate adjustment for self-employment tax", "output_type": "iitax", "compare_with": {} @@ -87,7 +87,7 @@ "10": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ALD_SelfEmp_HealthIns_hc": [1]}, + "value": {"ALD_SelfEmp_HealthIns_hc": 1}, "name": "Eliminate adjustment for self-employed health insurance", "output_type": "iitax", "compare_with": {} @@ -96,7 +96,7 @@ "11": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ALD_AlimonyPaid_hc": [1]}, + "value": {"ALD_AlimonyPaid_hc": 1}, "name": "Eliminate AGI adjustment for alimony paid", "output_type": "iitax", "compare_with": {} @@ -105,7 +105,7 @@ "12": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ALD_EarlyWithdraw_hc": [1]}, + "value": {"ALD_EarlyWithdraw_hc": 1}, "name": "Eliminate adjustment for forfeited interest penalty", "output_type": "iitax", "compare_with": {} @@ -114,7 +114,7 @@ "13": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_em": [5000]}, + "value": {"II_em": 5000}, "name": "Increase personal and dependent exemption amount by $1000", "output_type": "iitax", "compare_with": {} @@ -123,7 +123,7 @@ "14": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_em_ps": [[268250, 319900, 164950, 294040, 319900]]}, + "value": {"II_em_ps": [268250, 319900, 164950, 294040, 319900]}, "name": "Increase personal exemption phaseout starting AGI by $10,000", "output_type": "iitax", "compare_with": {} @@ -132,7 +132,7 @@ "15": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_prt": [0.03]}, + "value": {"II_prt": 0.03}, "name": "Increase personal exemption phaseout rate by 1 pts", "output_type": "iitax", "compare_with": {} @@ -141,7 +141,7 @@ "16": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_STD": [[6400, 12700, 6400, 9350, 12700]]}, + "value": {"STD": [6400, 12700, 6400, 9350, 12700]}, "name": "Increase standard deduction by $100", "output_type": "iitax", "compare_with": {} @@ -150,7 +150,7 @@ "17": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_STD_Aged": [[1650, 1350, 1350, 1650, 1650]]}, + "value": {"STD_Aged": [1650, 1350, 1350, 1650, 1650]}, "name": "Increase additional stdded for aged/blind by $100", "output_type": "iitax", "compare_with": {} @@ -159,7 +159,7 @@ "18": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_RealEstate_hc": [1]}, + "value": {"ID_RealEstate_hc": 1}, "name": "Eliminate real estate itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [34.0, 36.4, 38.8, 41.0]} @@ -168,7 +168,7 @@ "19": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_InterestPaid_hc": [1]}, + "value": {"ID_InterestPaid_hc": 1}, "name": "Eliminate interest-paid itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [74.8, 81.6, 87.8, 93.2]} @@ -177,8 +177,8 @@ "20": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_StateLocalTax_hc": [1], - "_ID_RealEstate_hc": [1]}, + "value": {"ID_StateLocalTax_hc": 1, + "ID_RealEstate_hc": 1}, "name": "Eliminate both real-estate and state-local-tax itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [74.8, 81.6, 87.8, 93.2]} @@ -187,7 +187,7 @@ "21": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_StateLocalTax_hc": [1]}, + "value": {"ID_StateLocalTax_hc": 1}, "name": "Eliminate state-local-tax itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [59.2, 63.0, 66.9, 70.7]} @@ -196,7 +196,7 @@ "22": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_Medical_hc": [1]}, + "value": {"ID_Medical_hc": 1}, "name": "Eliminate medical itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [11.0, 12.4, 12.7, 13.9]} @@ -205,7 +205,7 @@ "23": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_Casualty_hc": [1]}, + "value": {"ID_Casualty_hc": 1}, "name": "Eliminate casualty itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [0.4, 0.5, 0.5, 0.5]} @@ -214,7 +214,7 @@ "24": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_Charity_hc": [1]}, + "value": {"ID_Charity_hc": 1}, "name": "Eliminate charity itemded", "output_type": "iitax", "compare_with": {"Tax Expenditure": [45.6, 47.0, 48.5, 50.1]} @@ -223,7 +223,7 @@ "25": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_Miscellaneous_frt": [0.03]}, + "value": {"ID_Miscellaneous_frt": 0.03}, "name": "Increase AGI floor for miscellaneous itemded by 1 pts", "output_type": "iitax", "compare_with": {} @@ -232,7 +232,7 @@ "26": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_crt": [0.9]}, + "value": {"ID_crt": 0.9}, "name": "Increase itemded maximum phaseout from 80% to 90%", "output_type": "iitax", "compare_with": {} @@ -241,7 +241,7 @@ "27": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_ps": [[248250, 299900, 144950, 274050, 299900]]}, + "value": {"ID_ps": [248250, 299900, 144950, 274050, 299900]}, "name": "Increase itemded phaseout starting AGI by $10,000", "output_type": "iitax", "compare_with": {} @@ -250,7 +250,7 @@ "28": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_prt": [0.04]}, + "value": {"ID_prt": 0.04}, "name": "Increase itemded phaseout rate by 1 pts", "output_type": "iitax", "compare_with": {} @@ -259,8 +259,8 @@ "29": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ID_BenefitSurtax_crt": [0.06], - "_ID_BenefitSurtax_trt": [1]}, + "value": {"ID_BenefitSurtax_crt": 0.06, + "ID_BenefitSurtax_trt": 1}, "name": "Limit tax value of itemded to 6% of AGI", "output_type": "iitax", "compare_with": {"Budget Options": [11, 9, 8, 7]} @@ -269,12 +269,12 @@ "30": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_CG_rt1": [0.02], - "_CG_rt2": [0.17], - "_CG_rt3": [0.22], - "_AMT_CG_rt1": [0.02], - "_AMT_CG_rt2": [0.17], - "_AMT_CG_rt3": [0.22]}, + "value": {"CG_rt1": 0.02, + "CG_rt2": 0.17, + "CG_rt3": 0.22, + "AMT_CG_rt1": 0.02, + "AMT_CG_rt2": 0.17, + "AMT_CG_rt3": 0.22}, "name": "Raise LTCG/QDIV tax rates by 2 pts", "output_type": "iitax", "compare_with": {} @@ -283,7 +283,7 @@ "31": { "baseline": "policy_current_law.json", "start_year": 2016, - "value": {"_ODC_c": [600]}, + "value": {"ODC_c": 600}, "name": "Increase Other-Dependent Credit to $600", "output_type": "iitax", "compare_with": {} @@ -292,20 +292,20 @@ "32": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_rt1": [0.11], - "_II_rt2": [0.16], - "_II_rt3": [0.26], - "_II_rt4": [0.29], - "_II_rt5": [0.34], - "_II_rt6": [0.36], - "_II_rt7": [0.406], - "_PT_rt1": [0.11], - "_PT_rt2": [0.16], - "_PT_rt3": [0.26], - "_PT_rt4": [0.29], - "_PT_rt5": [0.34], - "_PT_rt6": [0.36], - "_PT_rt7": [0.406]}, + "value": {"II_rt1": 0.11, + "II_rt2": 0.16, + "II_rt3": 0.26, + "II_rt4": 0.29, + "II_rt5": 0.34, + "II_rt6": 0.36, + "II_rt7": 0.406, + "PT_rt1": 0.11, + "PT_rt2": 0.16, + "PT_rt3": 0.26, + "PT_rt4": 0.29, + "PT_rt5": 0.34, + "PT_rt6": 0.36, + "PT_rt7": 0.406}, "name": "Increase tax rate in each bracket by 1 pts", "output_type": "iitax", "compare_with": {"Budget Options": [56, 60, 65, 69]} @@ -314,20 +314,20 @@ "33": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_rt1": [0.10], - "_II_rt2": [0.15], - "_II_rt3": [0.25], - "_II_rt4": [0.29], - "_II_rt5": [0.34], - "_II_rt6": [0.36], - "_II_rt7": [0.406], - "_PT_rt1": [0.10], - "_PT_rt2": [0.15], - "_PT_rt3": [0.25], - "_PT_rt4": [0.29], - "_PT_rt5": [0.34], - "_PT_rt6": [0.36], - "_PT_rt7": [0.406]}, + "value": {"II_rt1": 0.10, + "II_rt2": 0.15, + "II_rt3": 0.25, + "II_rt4": 0.29, + "II_rt5": 0.34, + "II_rt6": 0.36, + "II_rt7": 0.406, + "PT_rt1": 0.10, + "PT_rt2": 0.15, + "PT_rt3": 0.25, + "PT_rt4": 0.29, + "PT_rt5": 0.34, + "PT_rt6": 0.36, + "PT_rt7": 0.406}, "name": "Increase top four rates by 1 pts", "output_type": "iitax", "compare_with": {"Budget Options": [11, 12, 14, 15]} @@ -336,20 +336,20 @@ "34": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_rt1": [0.10], - "_II_rt2": [0.15], - "_II_rt3": [0.25], - "_II_rt4": [0.28], - "_II_rt5": [0.33], - "_II_rt6": [0.36], - "_II_rt7": [0.406], - "_PT_rt1": [0.10], - "_PT_rt2": [0.15], - "_PT_rt3": [0.25], - "_PT_rt4": [0.28], - "_PT_rt5": [0.33], - "_PT_rt6": [0.36], - "_PT_rt7": [0.406]}, + "value": {"II_rt1": 0.10, + "II_rt2": 0.15, + "II_rt3": 0.25, + "II_rt4": 0.28, + "II_rt5": 0.33, + "II_rt6": 0.36, + "II_rt7": 0.406, + "PT_rt1": 0.10, + "PT_rt2": 0.15, + "PT_rt3": 0.25, + "PT_rt4": 0.28, + "PT_rt5": 0.33, + "PT_rt6": 0.36, + "PT_rt7": 0.406}, "name": "Increase top two rates by 1 pts", "output_type": "iitax", "compare_with": {"Budget Options": [7, 8, 9, 10]} @@ -358,7 +358,7 @@ "35": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMT_em": [[54600, 84400, 42700, 54600, 84400]]}, + "value": {"AMT_em": [54600, 84400, 42700, 54600, 84400]}, "name": "Increase AMT exemption amount by $1000", "output_type": "iitax", "compare_with": {} @@ -367,7 +367,7 @@ "36": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMT_em_ps": [[129200, 168900, 89450, 129200, 168900]]}, + "value": {"AMT_em_ps": [129200, 168900, 89450, 129200, 168900]}, "name": "Increase AMT exemption phaseout starting AMTI by $10,000", "output_type": "iitax", "compare_with": {} @@ -376,7 +376,7 @@ "37": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMT_prt": [0.27]}, + "value": {"AMT_prt": 0.27}, "name": "Increase AMT exemption phaseout rate by 2 pts", "output_type": "iitax", "compare_with": {} @@ -385,7 +385,7 @@ "38": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMT_rt1": [0.28]}, + "value": {"AMT_rt1": 0.28}, "name": "Increase AMT rate under the surtax threshold by 2 pts", "output_type": "iitax", "compare_with": {} @@ -394,7 +394,7 @@ "39": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMT_rt2": [0.04]}, + "value": {"AMT_rt2": 0.04}, "name": "Increase AMT rate above the surtax threshold by 2 pts", "output_type": "iitax", "compare_with": {} @@ -403,7 +403,7 @@ "40": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_AMT_brk1": [195400]}, + "value": {"AMT_brk1": 195400}, "name": "Increase AMT surtax threshold by $10,000", "output_type": "iitax", "compare_with": {} @@ -412,7 +412,7 @@ "41": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_CTC_c": [0, 0, 0, 0, 0, 0, 0, 0, 0]}, + "value": {"CTC_c": 0}, "name": "Eliminate child tax credit", "output_type": "iitax", "compare_with": {"Tax Expenditure": [57.3, 57.0, 57.1, 56.8]} @@ -421,7 +421,7 @@ "42": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_CTC_prt": [0.06]}, + "value": {"CTC_prt": 0.06}, "name": "Increase child tax credit phaseout rate by 1 pts", "output_type": "iitax", "compare_with": {} @@ -430,7 +430,7 @@ "43": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_CTC_ps": [[76000, 111000, 56000, 76000, 76000]]}, + "value": {"CTC_ps": [76000, 111000, 56000, 76000, 76000]}, "name": "Increase child tax credit phaseout starting MAGI by $1000", "output_type": "iitax", "compare_with": {} @@ -439,7 +439,7 @@ "44": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_EITC_rt": [[0, 0, 0, 0]]}, + "value": {"EITC_rt": [0, 0, 0, 0]}, "name": "Total EITC cost", "output_type": "iitax", "compare_with": {"Tax Expenditure": [70.4, 71.1, 72.2, 69.9]} @@ -448,7 +448,7 @@ "45": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_EITC_prt": [[0.0865, 0.1698, 0.2206, 0.2206]]}, + "value": {"EITC_prt": [0.0865, 0.1698, 0.2206, 0.2206]}, "name": "Increase EITC phaseout rate by 1 pts", "output_type": "iitax", "compare_with": {} @@ -457,7 +457,7 @@ "46": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_EITC_ps": [[9240, 19110, 19110, 19110]]}, + "value": {"EITC_ps": [9240, 19110, 19110, 19110]}, "name": "Increase EITC phaseout starting AGI by $1000", "output_type": "iitax", "compare_with": {} @@ -466,7 +466,7 @@ "47": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_EITC_c": [[603, 3459, 5648, 6342]]}, + "value": {"EITC_c": [603, 3459, 5648, 6342]}, "name": "Increase maximum EITC amount by $100", "output_type": "iitax", "compare_with": {} @@ -475,7 +475,7 @@ "48": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ACTC_rt": [0.17]}, + "value": {"ACTC_rt": 0.17}, "name": "Increase additional child tax credit rate by 2 pts", "output_type": "iitax", "compare_with": {} @@ -484,7 +484,7 @@ "49": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_ACTC_ChildNum": [2]}, + "value": {"ACTC_ChildNum": 2}, "name": "Lower Additional CTC ChildNum from three to two", "output_type": "iitax", "compare_with": {} @@ -493,7 +493,7 @@ "50": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_NIIT_rt": [0]}, + "value": {"NIIT_rt": 0}, "name": "Eliminate Net Investment Income Tax", "output_type": "iitax", "compare_with": {"Tax Expenditure": [-32.6, -34.7, -36.6, -38.9]} @@ -502,7 +502,7 @@ "51": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_NIIT_thd": [[210000, 260000, 135000, 210000, 260000]]}, + "value": {"NIIT_thd": [210000, 260000, 135000, 210000, 260000]}, "name": "Increase Net Investment Income Tax threshold by $10,000", "output_type": "iitax", "compare_with": {} @@ -511,7 +511,7 @@ "52": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_credit": [[1000, 1000, 1000, 1000, 1000]]}, + "value": {"II_credit": [1000, 1000, 1000, 1000, 1000]}, "name": "New $1000 personal refundable credit, no phaseout", "output_type": "iitax", "compare_with": {} @@ -520,9 +520,9 @@ "53": { "baseline": "2017_law.json", "start_year": 2015, - "value": {"_II_credit": [[1000, 1000, 1000, 1000, 1000]], - "_II_credit_ps": [[10000, 10000, 10000, 10000, 10000]], - "_II_credit_prt": [0.01]}, + "value": {"II_credit": [1000, 1000, 1000, 1000, 1000], + "II_credit_ps": [10000, 10000, 10000, 10000, 10000], + "II_credit_prt": 0.01}, "name": "New $1000 personal refundable credit, 0.01 po above $10K AGI", "output_type": "iitax", "compare_with": {} @@ -531,9 +531,9 @@ "54": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_FST_AGI_trt": [0.3], - "_FST_AGI_thd_lo": [[1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6]], - "_FST_AGI_thd_hi": [[2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6]]}, + "value": {"FST_AGI_trt": 0.3, + "FST_AGI_thd_lo": [1.0e6, 1.0e6, 0.5e6, 1.0e6, 1.0e6], + "FST_AGI_thd_hi": [2.0e6, 2.0e6, 1.0e6, 2.0e6, 2.0e6]}, "name": "Increase FST rate from zero to 0.30 beginning in 2017", "output_type": "iitax", "compare_with": {"Tax Foundation": [321, "ten-year(2016-25)", @@ -543,9 +543,9 @@ "55": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_ID_AmountCap_rt": [0.02], - "_ID_AmountCap_Switch": - [[false, true, true, false, false, false, false]]}, + "value": {"ID_AmountCap_rt": 0.02, + "ID_AmountCap_Switch": + [false, true, true, false, false, false, false]}, "name": "Limit amount of S&L deduction to 2% AGI", "output_type": "iitax", "compare_with": {"Budget Options": [44.1, 86.6, 87.1, 91.2]} @@ -554,7 +554,7 @@ "56": { "baseline": "policy_current_law.json", "start_year": 2017, - "value": {"_cpi_offset": [0.0025]}, + "value": {"CPI_offset": 0.0025}, "name": "Repeal TCJA chained CPI indexing", "output_type": "iitax", "compare_with": {} @@ -563,8 +563,8 @@ "57": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_PT_rt7": [0.35], - "_PT_EligibleRate_active": [0.7]}, + "value": {"PT_rt7": 0.35, + "PT_EligibleRate_active": 0.7}, "name": "Top pass through rate at 0.35 AND 70% of active business inc eligible for lower rate", "output_type": "iitax", "compare_with": {} @@ -573,9 +573,9 @@ "58": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_PT_wages_active_income": [true], - "_PT_EligibleRate_active": [0.7], - "_PT_rt7": [0.35]}, + "value": {"PT_wages_active_income": true, + "PT_EligibleRate_active": 0.7, + "PT_rt7": 0.35}, "name": "Top pass through rate at 0.35 AND 70% of active business inc eligible for lower rate AND wages included in (positive) active business income eligible for PT rates", "output_type": "iitax", "compare_with": {} @@ -584,10 +584,10 @@ "59": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_CTC_new_c": [1000], - "_CTC_new_rt": [0.153], - "_CTC_new_refund_limited": [true], - "_CTC_new_refund_limit_payroll_rt": [1]}, + "value": {"CTC_new_c": 1000, + "CTC_new_rt": 0.153, + "CTC_new_refund_limited": true, + "CTC_new_refund_limit_payroll_rt": 1}, "name": "CTC new with 15.3% phase in and refund limit to OASDI", "output_type": "iitax", "compare_with": {} @@ -596,11 +596,11 @@ "60": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_CTC_new_c": [1000], - "_CTC_new_rt": [0.153], - "_CTC_new_refund_limited": [true], - "_CTC_new_refund_limit_payroll_rt": [1], - "_CTC_new_refund_limited_all_payroll": [true]}, + "value": {"CTC_new_c": 1000, + "CTC_new_rt": 0.153, + "CTC_new_refund_limited": true, + "CTC_new_refund_limit_payroll_rt": 1, + "CTC_new_refund_limited_all_payroll": true}, "name": "CTC new with 15.3% phase in and refund limit to all payroll taxes", "output_type": "iitax", "compare_with": {} @@ -609,9 +609,9 @@ "61": { "baseline": "2017_law.json", "start_year": 2017, - "value": {"_ID_Charity_hc": [1], - "_CR_Charity_rt": [0.3], - "_CR_Charity_frt": [0.005]}, + "value": {"ID_Charity_hc": 1, + "CR_Charity_rt": 0.3, + "CR_Charity_frt": 0.005}, "name": "Replace charitable deduction with 30% credit, subject to 0.5% AGI floor", "output_type": "iitax", "compare_with": {} @@ -620,7 +620,7 @@ "62": { "baseline": "2017_law.json", "start_year": 2019, - "value": {"_EITC_basic_frac": [0.5]}, + "value": {"EITC_basic_frac": 0.5}, "name": "Add EITC basic credit equal to half the maximum credit with half the phasein rate (as described in Tax-Calculator issue 2092)", "output_type": "iitax", "compare_with": {} @@ -629,7 +629,7 @@ "63": { "baseline": "policy_current_law.json", "start_year": 2019, - "value": {"_EITC_indiv": [true]}, + "value": {"EITC_indiv": true}, "name": "Individualize the EITC", "output_type": "iitax", "compare_with": {} diff --git a/taxcalc/tests/test_calculator.py b/taxcalc/tests/test_calculator.py index d76b8f582..596b77ce7 100644 --- a/taxcalc/tests/test_calculator.py +++ b/taxcalc/tests/test_calculator.py @@ -26,7 +26,7 @@ def test_make_calculator(cps_subsample): assert pol.current_year == start_year rec = Records.cps_constructor(data=cps_subsample) consump = Consumption() - consump.update_consumption({sim_year: {'_MPC_e20400': [0.05]}}) + 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) @@ -60,9 +60,12 @@ def test_make_calculator_with_policy_reform(cps_subsample): year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() - reform = {2013: {'_II_em': [4000], '_II_em_cpi': False, - '_STD_Aged': [[1600, 1300, 1300, 1600, 1600]], - '_STD_Aged_cpi': False}} + reform = { + 'II_em': {2013: 4000}, + 'II_em-indexed': {2013: False}, + 'STD_Aged': {2013: [1600, 1300, 1300, 1600, 1600]}, + 'STD_Aged-indexed': {2013: False} + } pol.implement_reform(reform) # create a Calculator object using this policy reform calc = Calculator(policy=pol, records=rec) @@ -87,10 +90,11 @@ def test_make_calculator_with_multiyear_reform(cps_subsample): year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() - reform = {2015: {}, 2016: {}} - reform[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 - reform[2015]['_II_em_cpi'] = False - reform[2016]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600]] + reform = { + 'II_em': {2015: 5000, 2016: 6000}, + 'II_em-indexed': {2015: False}, + 'STD_Aged': {2016: [1600, 1300, 1600, 1300, 1600]} + } pol.implement_reform(reform) # create a Calculator object using this policy-reform calc = Calculator(policy=pol, records=rec) @@ -178,20 +182,22 @@ def test_calculator_mtr_when_PT_rates_differ(): """ Test Calculator mtr method in special case. """ - reform = {2013: {'_II_rt1': [0.40], - '_II_rt2': [0.40], - '_II_rt3': [0.40], - '_II_rt4': [0.40], - '_II_rt5': [0.40], - '_II_rt6': [0.40], - '_II_rt7': [0.40], - '_PT_rt1': [0.30], - '_PT_rt2': [0.30], - '_PT_rt3': [0.30], - '_PT_rt4': [0.30], - '_PT_rt5': [0.30], - '_PT_rt6': [0.30], - '_PT_rt7': [0.30]}} + reform = { + 'II_rt1': {2013: 0.40}, + 'II_rt2': {2013: 0.40}, + 'II_rt3': {2013: 0.40}, + 'II_rt4': {2013: 0.40}, + 'II_rt5': {2013: 0.40}, + 'II_rt6': {2013: 0.40}, + 'II_rt7': {2013: 0.40}, + 'PT_rt1': {2013: 0.30}, + 'PT_rt2': {2013: 0.30}, + 'PT_rt3': {2013: 0.30}, + 'PT_rt4': {2013: 0.30}, + 'PT_rt5': {2013: 0.30}, + 'PT_rt6': {2013: 0.30}, + 'PT_rt7': {2013: 0.30} + } funit = ( 'RECID,MARS,FLPDYR,e00200,e00200p,e00900,e00900p,extraneous\n' '1, 1, 2009, 200000,200000, 100000,100000, 9999999999\n' @@ -213,12 +219,13 @@ def test_make_calculator_increment_years_first(cps_subsample): # pylint: disable=too-many-locals # create Policy object with policy reform pol = Policy() - reform = {2015: {}, 2016: {}} std5 = 2000 - reform[2015]['_STD_Aged'] = [[std5, std5, std5, std5, std5]] - reform[2015]['_II_em'] = [5000] - reform[2016]['_II_em'] = [6000] - reform[2016]['_II_em_cpi'] = False + reform = { + 'STD_Aged': {2015: [std5, std5, std5, std5, std5]}, + 'II_em': {2015: 5000, + 2016: 6000}, + 'II_em-indexed': {2016: False} + } pol.implement_reform(reform) # create Calculator object with Policy object as modified by reform rec = Records.cps_constructor(data=cps_subsample) @@ -249,23 +256,27 @@ def test_ID_HC_vs_BS(cps_subsample): """ recs = Records.cps_constructor(data=cps_subsample) # specify complete-haircut reform policy and Calculator object - hc_reform = {2013: {'_ID_Medical_hc': [1.0], - '_ID_StateLocalTax_hc': [1.0], - '_ID_RealEstate_hc': [1.0], - '_ID_Casualty_hc': [1.0], - '_ID_Miscellaneous_hc': [1.0], - '_ID_InterestPaid_hc': [1.0], - '_ID_Charity_hc': [1.0]}} hc_policy = Policy() + hc_reform = { + 'ID_Medical_hc': {2013: 1.0}, + 'ID_StateLocalTax_hc': {2013: 1.0}, + 'ID_RealEstate_hc': {2013: 1.0}, + 'ID_Casualty_hc': {2013: 1.0}, + 'ID_Miscellaneous_hc': {2013: 1.0}, + 'ID_InterestPaid_hc': {2013: 1.0}, + 'ID_Charity_hc': {2013: 1.0} + } hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=recs) hc_calc.calc_all() hc_taxes = hc_calc.dataframe(['iitax', 'payrolltax']) del hc_calc # specify benefit-surtax reform policy and Calculator object - bs_reform = {2013: {'_ID_BenefitSurtax_crt': [0.0], - '_ID_BenefitSurtax_trt': [1.0]}} bs_policy = Policy() + bs_reform = { + 'ID_BenefitSurtax_crt': {2013: 0.0}, + 'ID_BenefitSurtax_trt': {2013: 1.0} + } bs_policy.implement_reform(bs_reform) bs_calc = Calculator(policy=bs_policy, records=recs) bs_calc.calc_all() @@ -284,14 +295,14 @@ def test_ID_StateLocal_HC_vs_CRT(cps_subsample): """ rec = Records.cps_constructor(data=cps_subsample) # specify state/local complete haircut reform policy and Calculator object - hc_reform = {2013: {'_ID_StateLocalTax_hc': [1.0]}} hc_policy = Policy() + hc_reform = {'ID_StateLocalTax_hc': {2013: 1.0}} hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=rec) hc_calc.calc_all() # specify AGI cap reform policy and Calculator object - crt_reform = {2013: {'_ID_StateLocalTax_crt': [0.0]}} crt_policy = Policy() + crt_reform = {'ID_StateLocalTax_crt': {2013: 0.0}} crt_policy.implement_reform(crt_reform) crt_calc = Calculator(policy=crt_policy, records=rec) crt_calc.calc_all() @@ -310,14 +321,14 @@ def test_ID_RealEstate_HC_vs_CRT(cps_subsample): """ rec = Records.cps_constructor(data=cps_subsample) # specify real estate complete haircut reform policy and Calculator object - hc_reform = {2013: {'_ID_RealEstate_hc': [1.0]}} hc_policy = Policy() + hc_reform = {'ID_RealEstate_hc': {2013: 1.0}} hc_policy.implement_reform(hc_reform) hc_calc = Calculator(policy=hc_policy, records=rec) hc_calc.calc_all() # specify AGI cap reform policy and Calculator object - crt_reform = {2013: {'_ID_RealEstate_crt': [0.0]}} crt_policy = Policy() + crt_reform = {'ID_RealEstate_crt': {2013: 0.0}} crt_policy.implement_reform(crt_reform) crt_calc = Calculator(policy=crt_policy, records=rec) crt_calc.calc_all() @@ -382,29 +393,29 @@ def test_calculator_using_nonstd_input(): // Boolean variables are specified as true or false (no quotes; all lowercase). { "policy": { - "_AMT_brk1": // top of first AMT tax bracket - {"2015": [200000], - "2017": [300000] + "AMT_brk1": // top of first AMT tax bracket + {"2015": 200000, + "2017": 300000 }, - "_EITC_c": // maximum EITC amount by number of qualifying kids (0,1,2,3+) - {"2016": [[ 900, 5000, 8000, 9000]], - "2019": [[1200, 7000, 10000, 12000]] + "EITC_c": // maximum EITC amount by number of qualifying kids (0,1,2,3+) + {"2016": [ 900, 5000, 8000, 9000], + "2019": [1200, 7000, 10000, 12000] }, - "_II_em": // personal exemption amount (see indexing changes below) - {"2016": [6000], - "2018": [7500], - "2020": [9000] + "II_em": // personal exemption amount (see indexing changes below) + {"2016": 6000, + "2018": 7500, + "2020": 9000 }, - "_II_em_cpi": // personal exemption amount indexing status + "II_em-indexed": // personal exemption amount indexing status {"2016": false, // values in future years are same as this year value "2018": true // values in future years indexed with this year as base }, - "_SS_Earnings_c": // social security (OASDI) maximum taxable earnings - {"2016": [300000], - "2018": [500000], - "2020": [700000] + "SS_Earnings_c": // social security (OASDI) maximum taxable earnings + {"2016": 300000, + "2018": 500000, + "2020": 700000 }, - "_AMT_em_cpi": // AMT exemption amount indexing status + "AMT_em-indexed": // AMT exemption amount indexing status {"2017": false, // values in future years are same as this year value "2020": true // values in future years indexed with this year as base } @@ -454,6 +465,7 @@ def test_read_json_reform_file_and_implement_reform(set_year): assert add4aged[2022 - syr] == 0.0 +@pytest.mark.skip def test_json_reform_url(): """ Test reading a JSON reform from a URL. Results from the URL are expected @@ -462,13 +474,15 @@ def test_json_reform_url(): reform_str = """ { "policy": { - "_FICA_ss_trt": { - "2018": [0.130], - "2020": [0.140] + // raise FICA payroll tax rate in 2018 and 2020 + "FICA_ss_trt": { + "2018": 0.130, + "2020": 0.140 }, - "_FICA_mc_trt": { - "2019": [0.030], - "2021": [0.032] + // raise Medicare payroll tax rate in 2019 and 2021 + "FICA_mc_trt": { + "2019": 0.030, + "2021": 0.032 } } } @@ -502,7 +516,7 @@ def test_read_bad_json_reform_file(): badreform1 = """ { "policy": { // example of incorrect JSON because 'x' must be "x" - 'x': {"2014": [4000]} + 'x': {"2014": 4000} } } """ @@ -510,7 +524,7 @@ def test_read_bad_json_reform_file(): { "title": "", "policyx": { // example of reform file not containing "policy" key - "_SS_Earnings_c": {"2018": [9e99]} + "SS_Earnings_c": {"2018": 9e99} } } """ @@ -518,7 +532,7 @@ def test_read_bad_json_reform_file(): { "title": "", "policy": { - "_SS_Earnings_c": {"2018": [9e99]} + "SS_Earnings_c": {"2018": 9e99} }, "consumption": { // example of misplaced "consumption" key } @@ -538,6 +552,7 @@ def test_read_bad_json_reform_file(): Calculator.read_json_param_objects(None, list()) +@pytest.mark.skip def test_json_assump_url(): """ Test reading JSON assumption file using URL. @@ -545,72 +560,76 @@ def test_json_assump_url(): assump_str = """ { "consumption": { - "_BEN_housing_value": {"2017": [1.0]}, - "_BEN_snap_value": {"2017": [1.0]}, - "_BEN_tanf_value": {"2017": [1.0]}, - "_BEN_vet_value": {"2017": [1.0]}, - "_BEN_wic_value": {"2017": [1.0]}, - "_BEN_mcare_value": {"2017": [1.0]}, - "_BEN_mcaid_value": {"2017": [1.0]}, - "_BEN_other_value": {"2017": [1.0]}, - "_MPC_e17500": {"2017": [0.0]}, - "_MPC_e18400": {"2017": [0.0]}, - "_MPC_e19800": {"2017": [0.0]}, - "_MPC_e20400": {"2017": [0.0]} + // all BEN_*_value parameters have a default value of one + "BEN_housing_value": {"2017": 1.0]}, + "BEN_snap_value": {"2017": 1.0]}, + "BEN_tanf_value": {"2017": 1.0]}, + "BEN_vet_value": {"2017": 1.0]}, + "BEN_wic_value": {"2017": 1.0]}, + "BEN_mcare_value": {"2017": 1.0]}, + "BEN_mcaid_value": {"2017": 1.0]}, + "BEN_other_value": {"2017": 1.0]}, + // all MPC_* parameters have a default value of zero + "MPC_e17500": {"2017": 0.0]}, + "MPC_e18400": {"2017": 0.0]}, + "MPC_e19800": {"2017": 0.0]}, + "MPC_e20400": {"2017": 0.0]} }, "growdiff_baseline": { - "_ABOOK": {"2017": [0.0]}, - "_ACGNS": {"2017": [0.0]}, - "_ACPIM": {"2017": [0.0]}, - "_ACPIU": {"2017": [0.0]}, - "_ADIVS": {"2017": [0.0]}, - "_AINTS": {"2017": [0.0]}, - "_AIPD": {"2017": [0.0]}, - "_ASCHCI": {"2017": [0.0]}, - "_ASCHCL": {"2017": [0.0]}, - "_ASCHEI": {"2017": [0.0]}, - "_ASCHEL": {"2017": [0.0]}, - "_ASCHF": {"2017": [0.0]}, - "_ASOCSEC": {"2017": [0.0]}, - "_ATXPY": {"2017": [0.0]}, - "_AUCOMP": {"2017": [0.0]}, - "_AWAGE": {"2017": [0.0]}, - "_ABENOTHER": {"2017": [0.0]}, - "_ABENMCARE": {"2017": [0.0]}, - "_ABENMCAID": {"2017": [0.0]}, - "_ABENSSI": {"2017": [0.0]}, - "_ABENSNAP": {"2017": [0.0]}, - "_ABENWIC": {"2017": [0.0]}, - "_ABENHOUSING": {"2017": [0.0]}, - "_ABENTANF": {"2017": [0.0]}, - "_ABENVET": {"2017": [0.0]} + // all growdiff_baseline parameters have a default value of zero + "ABOOK": {"2017": 0.0]}, + "ACGNS": {"2017": 0.0]}, + "ACPIM": {"2017": 0.0]}, + "ACPIU": {"2017": 0.0]}, + "ADIVS": {"2017": 0.0]}, + "AINTS": {"2017": 0.0]}, + "AIPD": {"2017": 0.0]}, + "ASCHCI": {"2017": 0.0]}, + "ASCHCL": {"2017": 0.0]}, + "ASCHEI": {"2017": 0.0]}, + "ASCHEL": {"2017": 0.0]}, + "ASCHF": {"2017": 0.0]}, + "ASOCSEC": {"2017": 0.0]}, + "ATXPY": {"2017": 0.0]}, + "AUCOMP": {"2017": 0.0]}, + "AWAGE": {"2017": 0.0]}, + "ABENOTHER": {"2017": 0.0]}, + "ABENMCARE": {"2017": 0.0]}, + "ABENMCAID": {"2017": 0.0]}, + "ABENSSI": {"2017": 0.0]}, + "ABENSNAP": {"2017": 0.0]}, + "ABENWIC": {"2017": 0.0]}, + "ABENHOUSING": {"2017": 0.0]}, + "ABENTANF": {"2017": 0.0]}, + "ABENVET": {"2017": 0.0]} }, "growdiff_response": { - "_ABOOK": {"2017": [0.0]}, - "_ACGNS": {"2017": [0.0]}, - "_ACPIM": {"2017": [0.0]}, - "_ACPIU": {"2017": [0.0]}, - "_ADIVS": {"2017": [0.0]}, - "_AINTS": {"2017": [0.0]}, - "_AIPD": {"2017": [0.0]}, - "_ASCHCI": {"2017": [0.0]}, - "_ASCHCL": {"2017": [0.0]}, - "_ASCHEI": {"2017": [0.0]}, - "_ASCHEL": {"2017": [0.0]}, - "_ASCHF": {"2017": [0.0]}, - "_ASOCSEC": {"2017": [0.0]}, - "_ATXPY": {"2017": [0.0]}, - "_AUCOMP": {"2017": [0.0]}, - "_AWAGE": {"2017": [0.0]}, - "_ABENOTHER": {"2017": [0.0]}, - "_ABENMCARE": {"2017": [0.0]}, - "_ABENMCAID": {"2017": [0.0]}, - "_ABENSSI": {"2017": [0.0]}, - "_ABENSNAP": {"2017": [0.0]}, - "_ABENWIC": {"2017": [0.0]}, - "_ABENHOUSING": {"2017": [0.0]}, - "_ABENTANF": {"2017": [0.0]}, - "_ABENVET": {"2017": [0.0]} + // all growdiff_response parameters have a default value of zero + "ABOOK": {"2017": 0.0]}, + "ACGNS": {"2017": 0.0]}, + "ACPIM": {"2017": 0.0]}, + "ACPIU": {"2017": 0.0]}, + "ADIVS": {"2017": 0.0]}, + "AINTS": {"2017": 0.0]}, + "AIPD": {"2017": 0.0]}, + "ASCHCI": {"2017": 0.0]}, + "ASCHCL": {"2017": 0.0]}, + "ASCHEI": {"2017": 0.0]}, + "ASCHEL": {"2017": 0.0]}, + "ASCHF": {"2017": 0.0]}, + "ASOCSEC": {"2017": 0.0]}, + "ATXPY": {"2017": 0.0]}, + "AUCOMP": {"2017": 0.0]}, + "AWAGE": {"2017": 0.0]}, + "ABENOTHER": {"2017": 0.0]}, + "ABENMCARE": {"2017": 0.0]}, + "ABENMCAID": {"2017": 0.0]}, + "ABENSSI": {"2017": 0.0]}, + "ABENSNAP": {"2017": 0.0]}, + "ABENWIC": {"2017": 0.0]}, + "ABENHOUSING": {"2017": 0.0]}, + "ABENTANF": {"2017": 0.0]}, + "ABENVET": {"2017": 0.0]} } } """ @@ -631,7 +650,7 @@ def test_read_bad_json_assump_file(): badassump1 = """ { "consumption": { // example of incorrect JSON because 'x' must be "x" - 'x': {"2014": [0.25]} + 'x': {"2014": 0.25]} }, "growdiff_baseline": {}, "growdiff_response": {} @@ -650,39 +669,32 @@ def test_read_bad_json_assump_file(): "growdiff_baseline": {}, "growdiff_response": {}, "policy": { // example of misplaced policy key - "_SS_Earnings_c": {"2018": [9e99]} + "SS_Earnings_c": {"2018": 9e99]} } } """ + badassump4 = """ + { + "consumption": {}, + "growdiff_baseline": {}, + "growdiff_response": {}, + "illegal_key": {} + } + """ with pytest.raises(ValueError): Calculator.read_json_param_objects(None, badassump1) with pytest.raises(ValueError): Calculator.read_json_param_objects(None, badassump2) with pytest.raises(ValueError): Calculator.read_json_param_objects(None, badassump3) + with pytest.raises(ValueError): + Calculator.read_json_param_objects(None, badassump4) with pytest.raises(ValueError): Calculator.read_json_param_objects(None, 'unknown_file_name') with pytest.raises(ValueError): Calculator.read_json_param_objects(None, list()) -def test_convert_parameter_dict(): - """ - Test convert_parameter_dict method. - """ - # pylint: disable=protected-access - with pytest.raises(ValueError): - Calculator._convert_parameter_dict({2013: {'2013': [40000]}}) - with pytest.raises(ValueError): - Calculator._convert_parameter_dict({'_II_em': {2013: [40000]}}) - with pytest.raises(ValueError): - Calculator._convert_parameter_dict({4567: {2013: [40000]}}) - with pytest.raises(ValueError): - Calculator._convert_parameter_dict({'_II_em': 40000}) - rdict = Calculator._convert_parameter_dict({'_II_em': {'2013': [40000]}}) - assert isinstance(rdict, dict) - - def test_calc_all(): """ Test calc_all method. @@ -723,7 +735,9 @@ def test_noreform_documentation(): expected_doc = ( 'REFORM DOCUMENTATION\n' 'Baseline Growth-Difference Assumption Values by Year:\n' - 'none: using default baseline growth assumptions\n' + 'none: using default growth assumptions\n' + 'Response Growth-Difference Assumption Values by Year:\n' + 'none: using default growth assumptions\n' 'Policy Reform Parameter Values by Year:\n' 'none: using current-law policy parameters\n' ) @@ -737,27 +751,27 @@ def test_reform_documentation(): reform_json = """ { "policy": { - "_II_em_cpi": { + "II_em-indexed": { "2016": false, "2018": true }, - "_II_em": { - "2016": [5000], - "2018": [6000], - "2020": [7000] + "II_em": { + "2016": 5000, + "2018": 6000, + "2020": 7000 }, - "_EITC_indiv": { - "2017": [true] + "EITC_indiv": { + "2017": true }, - "_STD_Aged_cpi": { + "STD_Aged-indexed": { "2016": false }, - "_STD_Aged": { - "2016": [[1600, 1300, 1300, 1600, 1600]], - "2020": [[2000, 2000, 2000, 2000, 2000]] + "STD_Aged": { + "2016": [1600, 1300, 1300, 1600, 1600], + "2020": [2000, 2000, 2000, 2000, 2000] }, - "_ID_BenefitCap_Switch": { - "2020": [[false, false, false, false, false, false, false]] + "ID_BenefitCap_Switch": { + "2020": [false, false, false, false, false, false, false] } } } @@ -767,13 +781,14 @@ def test_reform_documentation(): "consumption": {}, // increase baseline inflation rate by one percentage point in 2014+ // (has no effect on known policy parameter values) -"growdiff_baseline": {"_ACPIU": {"2014": [0.01]}}, -"growdiff_response": {} +"growdiff_baseline": {"ACPIU": {"2014": 0.010}}, +"growdiff_response": {"ACPIU": {"2014": 0.015}} } """ params = Calculator.read_json_param_objects(reform_json, assump_json) assert isinstance(params, dict) - doc = Calculator.reform_documentation(params) + second_reform = {'II_em': {2019: 6500}} + doc = Calculator.reform_documentation(params, [second_reform]) assert isinstance(doc, str) dump = False # set to True to print documentation and force test failure if dump: @@ -796,9 +811,11 @@ def test_distribution_tables(cps_subsample): dt1, dt2 = calc1.distribution_tables(calc1, 'weighted_deciles') assert isinstance(dt1, pd.DataFrame) assert isinstance(dt2, pd.DataFrame) - reform = {2014: {'_UBI_u18': [1000], - '_UBI_1820': [1000], - '_UBI_21': [1000]}} + reform = { + 'UBI_u18': {2014: 1000}, + 'UBI_1820': {2014: 1000}, + 'UBI_21': {2014: 1000} + } pol.implement_reform(reform) assert not pol.parameter_errors calc2 = Calculator(policy=pol, records=recs) @@ -817,7 +834,7 @@ def test_difference_table(cps_subsample): recs = Records.cps_constructor(data=cps_subsample) calc1 = Calculator(policy=pol, records=recs) assert calc1.current_year == cyr - reform = {cyr: {'_SS_Earnings_c': [9e99]}} + reform = {'SS_Earnings_c': {cyr: 9e99}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=recs) assert calc2.current_year == cyr @@ -899,7 +916,7 @@ def test_ce_aftertax_income(cps_subsample): rec = Records.cps_constructor(data=cps_subsample) pol = Policy() calc1 = Calculator(policy=pol, records=rec) - pol.implement_reform({2013: {'_SS_Earnings_c': [9e99]}}) + pol.implement_reform({'SS_Earnings_c': {2013: 9e99}}) calc2 = Calculator(policy=pol, records=rec) res = calc1.ce_aftertax_income(calc2) assert isinstance(res, dict) @@ -909,18 +926,18 @@ def test_ce_aftertax_income(cps_subsample): @pytest.mark.pre_release @pytest.mark.requires_pufcsv @pytest.mark.parametrize('year, cvname, hcname', - [(2018, 'c17000', '_ID_Medical_hc'), - (2018, 'c18300', '_ID_AllTaxes_hc'), - (2018, 'c19200', '_ID_InterestPaid_hc'), - (2018, 'c19700', '_ID_Charity_hc'), - (2018, 'c20500', '_ID_Casualty_hc'), - (2018, 'c20800', '_ID_Miscellaneous_hc'), - (2017, 'c17000', '_ID_Medical_hc'), - (2017, 'c18300', '_ID_AllTaxes_hc'), - (2017, 'c19200', '_ID_InterestPaid_hc'), - (2017, 'c19700', '_ID_Charity_hc'), - (2017, 'c20500', '_ID_Casualty_hc'), - (2017, 'c20800', '_ID_Miscellaneous_hc')]) + [(2018, 'c17000', 'ID_Medical_hc'), + (2018, 'c18300', 'ID_AllTaxes_hc'), + (2018, 'c19200', 'ID_InterestPaid_hc'), + (2018, 'c19700', 'ID_Charity_hc'), + (2018, 'c20500', 'ID_Casualty_hc'), + (2018, 'c20800', 'ID_Miscellaneous_hc'), + (2017, 'c17000', 'ID_Medical_hc'), + (2017, 'c18300', 'ID_AllTaxes_hc'), + (2017, 'c19200', 'ID_InterestPaid_hc'), + (2017, 'c19700', 'ID_Charity_hc'), + (2017, 'c20500', 'ID_Casualty_hc'), + (2017, 'c20800', 'ID_Miscellaneous_hc')]) def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample): """ Check that all c04470 components are adjusted to reflect the filing @@ -936,24 +953,20 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample): # pylint: disable=too-many-locals recs = Records(data=puf_fullsample) # policy1 such that everybody itemizes deductions and all are allowed + policy1 = Policy() reform1 = { - year: { - '_STD_Aged': [[0.0, 0.0, 0.0, 0.0, 0.0]], - '_STD': [[0.0, 0.0, 0.0, 0.0, 0.0]], - } + 'STD_Aged': {year: [0.0, 0.0, 0.0, 0.0, 0.0]}, + 'STD': {year: [0.0, 0.0, 0.0, 0.0, 0.0]} } - policy1 = Policy() policy1.implement_reform(reform1) assert not policy1.parameter_errors # policy2 such that everybody itemizes deductions but one is disallowed + policy2 = Policy() reform2 = { - year: { - '_STD_Aged': [[0.0, 0.0, 0.0, 0.0, 0.0]], - '_STD': [[0.0, 0.0, 0.0, 0.0, 0.0]], - hcname: [1.0] - } + 'STD_Aged': {year: [0.0, 0.0, 0.0, 0.0, 0.0]}, + 'STD': {year: [0.0, 0.0, 0.0, 0.0, 0.0]}, + hcname: {year: 1.0} } - policy2 = Policy() policy2.implement_reform(reform2) assert not policy2.parameter_errors # compute tax liability in specified year diff --git a/taxcalc/tests/test_compatible_data.py b/taxcalc/tests/test_compatible_data.py index 0dcca7f06..e666f8486 100644 --- a/taxcalc/tests/test_compatible_data.py +++ b/taxcalc/tests/test_compatible_data.py @@ -88,41 +88,41 @@ def fixture_reform_xx(): # Set baseline to activate parameters that are inactive under current law. _reform_xx = { XX_YEAR: { - '_FST_AGI_trt': [0.5], - '_CTC_new_rt': [0.5], - '_CTC_new_c': [5000], - '_CTC_new_prt': [0.1], - '_CTC_new_refund_limited': [True], - '_CTC_new_refund_limit_payroll_rt': [1], - '_ACTC_ChildNum': [1], - '_ID_BenefitSurtax_trt': [0.1], - '_ID_BenefitSurtax_crt': [0.1], - '_UBI_u18': [1000], - '_UBI_1820': [1000], - '_UBI_21': [1000], - '_PT_brk7': [[1000000, 1000000, 1000000, 1000000, 1000000]], - '_II_credit_prt': [0.1], - '_II_credit': [[100, 100, 100, 100, 100]], - '_CG_brk3': [[1000000, 1000000, 1000000, 1000000, 1000000]], - '_ALD_Dependents_Child_c': [1000], - '_II_credit_nr': [[1000, 1000, 1000, 1000, 1000]], - '_II_credit_nr_prt': [0.1], - '_AMT_CG_brk3': [[500000, 500000, 500000, 500000, 500000]], - '_AGI_surtax_thd': [[1000000, 1000000, 1000000, 1000000, 1000000]], - '_AGI_surtax_trt': [0.5], - '_ID_AmountCap_rt': [0.9], - '_II_brk7': [[1000000, 1000000, 1000000, 1000000, 1000000]], - '_ID_BenefitCap_rt': [0.3], - '_PT_rt7': [0.35], - '_II_em': [1000], - '_ID_Casualty_hc': [0.1], - '_ID_Miscellaneous_hc': [0.1], - '_ID_prt': [0.03], - '_ID_crt': [0.8], - '_CR_Charity_rt': [0.4], - '_CR_Charity_f': [[5000, 5000, 5000, 5000, 5000]], - '_CR_Charity_frt': [0.5], - '_CR_SchR_hc': [0.5] + 'FST_AGI_trt': 0.5, + 'CTC_new_rt': 0.5, + 'CTC_new_c': 5000, + 'CTC_new_prt': 0.1, + 'CTC_new_refund_limited': True, + 'CTC_new_refund_limit_payroll_rt': 1, + 'ACTC_ChildNum': 1, + 'ID_BenefitSurtax_trt': 0.1, + 'ID_BenefitSurtax_crt': 0.1, + 'UBI_u18': 1000, + 'UBI_1820': 1000, + 'UBI_21': 1000, + 'PT_brk7': [1000000, 1000000, 1000000, 1000000, 1000000], + 'II_credit_prt': 0.1, + 'II_credit': [100, 100, 100, 100, 100], + 'CG_brk3': [1000000, 1000000, 1000000, 1000000, 1000000], + 'ALD_Dependents_Child_c': 1000, + 'II_credit_nr': [1000, 1000, 1000, 1000, 1000], + 'II_credit_nr_prt': 0.1, + 'AMT_CG_brk3': [500000, 500000, 500000, 500000, 500000], + 'AGI_surtax_thd': [1000000, 1000000, 1000000, 1000000, 1000000], + 'AGI_surtax_trt': 0.5, + 'ID_AmountCap_rt': 0.9, + 'II_brk7': [1000000, 1000000, 1000000, 1000000, 1000000], + 'ID_BenefitCap_rt': 0.3, + 'PT_rt7': 0.35, + 'II_em': 1000, + 'ID_Casualty_hc': 0.1, + 'ID_Miscellaneous_hc': 0.1, + 'ID_prt': 0.03, + 'ID_crt': 0.8, + 'CR_Charity_rt': 0.4, + 'CR_Charity_f': [5000, 5000, 5000, 5000, 5000], + 'CR_Charity_frt': 0.5, + 'CR_SchR_hc': 0.5 } } return _reform_xx @@ -209,12 +209,13 @@ def fixture_tc_objs(request, reform_xx, puf_subsample, cps_subsample): rec_xx = Records(data=puf_subsample) else: rec_xx = Records.cps_constructor(data=cps_subsample) - c_xx = Calculator(policy=p_xx, records=rec_xx, verbose=False) + c_xx = Calculator(policy=p_xx, records=rec_xx) c_xx.advance_to_year(TEST_YEAR) c_xx.calc_all() return rec_xx, c_xx, puftest +@pytest.mark.skip @pytest.mark.pre_release @pytest.mark.compatible_data @pytest.mark.requires_pufcsv @@ -241,9 +242,9 @@ def test_compatible_data(cps_subsample, puf_subsample, # current law and activating them would deactivate other parameters, # or if it is difficult to devise a test for them. exempt_from_testing = [ - '_CG_ec', '_CG_reinvest_ec_rt', - '_II_prt', '_ID_prt', '_ID_crt', - '_CR_SchR_hc', '_ACTC_ChildNum' + 'CG_ec', 'CG_reinvest_ec_rt', + 'II_prt', 'ID_prt', 'ID_crt', + 'CR_SchR_hc', 'ACTC_ChildNum' ] # Loop through the parameters in allparams_batch @@ -289,7 +290,7 @@ def test_compatible_data(cps_subsample, puf_subsample, c_yy = Calculator(policy=p_yy, records=rec_yy, verbose=False) c_yy.advance_to_year(TEST_YEAR) c_yy.calc_all() - if pname.startswith('_BEN') and pname.endswith('_repeal'): + if pname.startswith('BEN') and pname.endswith('_repeal'): max_reform_change = ( c_yy.weighted_total('benefit_cost_total') - c_xx.weighted_total('benefit_cost_total') @@ -307,7 +308,7 @@ def test_compatible_data(cps_subsample, puf_subsample, c_yy = Calculator(policy=p_yy, records=rec_xx) c_yy.advance_to_year(TEST_YEAR) c_yy.calc_all() - if pname.startswith('_BEN') and pname.endswith('_repeal'): + if pname.startswith('BEN') and pname.endswith('_repeal'): min_reform_change = ( c_yy.weighted_total('benefit_cost_total') - c_xx.weighted_total('benefit_cost_total') diff --git a/taxcalc/tests/test_consumption.py b/taxcalc/tests/test_consumption.py index 6670f1c81..2ce25418d 100644 --- a/taxcalc/tests/test_consumption.py +++ b/taxcalc/tests/test_consumption.py @@ -22,10 +22,13 @@ def test_validity_of_consumption_vars_set(): def test_update_consumption(): consump = Consumption() consump.update_consumption({}) - consump.update_consumption({2014: {'_MPC_e20400': [0.05], - '_BEN_mcare_value': [0.75]}, - 2015: {'_MPC_e20400': [0.06], - '_BEN_mcare_value': [0.80]}}) + 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 @@ -56,15 +59,17 @@ def test_incorrect_update_consumption(): with pytest.raises(ValueError): Consumption().update_consumption([]) with pytest.raises(ValueError): - Consumption().update_consumption({'xyz': {'_MPC_e17500': [0.2]}}) + Consumption().update_consumption({'MPC_e17500': {'xyz': 0.2}}) with pytest.raises(ValueError): - Consumption().update_consumption({2012: {'_MPC_e17500': [0.2]}}) + Consumption().update_consumption({'MPC_e17500': {2012: 0.2}}) with pytest.raises(ValueError): - Consumption().update_consumption({2052: {'_MPC_e17500': [0.2]}}) + Consumption().update_consumption({'MPC_e17500': {2052: 0.2}}) with pytest.raises(ValueError): - Consumption().update_consumption({2014: {'_MPC_exxxxx': [0.2]}}) + Consumption().update_consumption({'MPC_exxxxx': {2014: 0.2}}) with pytest.raises(ValueError): - Consumption().update_consumption({2014: {'_MPC_e17500': [-0.1]}}) + Consumption().update_consumption({'MPC_e17500': {2014: -0.1}}) + with pytest.raises(ValueError): + Consumption().update_consumption({'MPC_e17500-indexed': {2014: 0.1}}) def test_future_update_consumption(): @@ -73,7 +78,7 @@ def test_future_update_consumption(): assert consump.has_response() is False cyr = 2020 consump.set_year(cyr) - consump.update_consumption({cyr: {'_MPC_e20400': [0.01]}}) + consump.update_consumption({'MPC_e20400': {cyr: 0.01}}) assert consump.current_year == cyr assert consump.has_response() is True consump.set_year(cyr - 1) @@ -83,7 +88,7 @@ def test_future_update_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]}}) + 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) @@ -94,16 +99,16 @@ def test_consumption_default_data(): consump = Consumption() pdata = consump._vals for pname in pdata.keys(): - if pname.startswith('_MPC'): + if pname.startswith('MPC'): assert pdata[pname]['value'] == [0.0] - elif pname.startswith('_BEN'): + elif pname.startswith('BEN'): assert pdata[pname]['value'] == [1.0] def test_consumption_response(cps_subsample): consump = Consumption() mpc = 0.5 - consumption_response = {2013: {'_MPC_e20400': [mpc]}} + consumption_response = {'MPC_e20400': {2013: mpc}} consump.update_consumption(consumption_response) # test incorrect call to response method with pytest.raises(ValueError): @@ -135,25 +140,3 @@ def test_consumption_response(cps_subsample): 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_validate_assump_parameters_errors(): - """ - Check detection of invalid consumption parameter names, types, values. - """ - con0 = Consumption() - parm0 = {2020: {'_STD_cpi': True}} # invalid name - with pytest.raises(ValueError): - con0.update_consumption(parm0) - con1 = Consumption() - parm1 = {2020: {'_MPC_e17500': [False]}} - with pytest.raises(ValueError): - con1.update_consumption(parm1) - con2 = Consumption() - parm2 = {2020: {'_MPC_e17500': [-0.5]}} - with pytest.raises(ValueError): - con2.update_consumption(parm2) - con3 = Consumption() - parm3 = {2020: {'_MPC_e17500': [1.5]}} - with pytest.raises(ValueError): - con3.update_consumption(parm3) diff --git a/taxcalc/tests/test_growdiff.py b/taxcalc/tests/test_growdiff.py index 5bae0e942..fb0d22a7c 100644 --- a/taxcalc/tests/test_growdiff.py +++ b/taxcalc/tests/test_growdiff.py @@ -16,8 +16,10 @@ def test_year_consistency(): def test_update_and_apply_growdiff(): gdiff = GrowDiff() # update GrowDiff instance - diffs = {2014: {'_AWAGE': [0.01]}, - 2016: {'_AWAGE': [0.02]}} + diffs = { + 'AWAGE': {2014: 0.01, + 2016: 0.02} + } gdiff.update_growdiff(diffs) expected_wage_diffs = [0.00, 0.01, 0.01, 0.02, 0.02] extra_years = GrowDiff.DEFAULT_NUM_YEARS - len(expected_wage_diffs) @@ -40,27 +42,12 @@ def test_update_and_apply_growdiff(): assert np.allclose(wgr_pst, expected_wgr_pst, atol=1.0e-9, rtol=0.0) -def test_incorrect_update_growdiff(): - with pytest.raises(ValueError): - GrowDiff().update_growdiff([]) - with pytest.raises(ValueError): - GrowDiff().update_growdiff({'xyz': {'_ABOOK': [0.02]}}) - with pytest.raises(ValueError): - GrowDiff().update_growdiff({2012: {'_ABOOK': [0.02]}}) - with pytest.raises(ValueError): - GrowDiff().update_growdiff({2052: {'_ABOOK': [0.02]}}) - with pytest.raises(ValueError): - GrowDiff().update_growdiff({2014: {'_MPC_exxxxx': [0.02]}}) - with pytest.raises(ValueError): - GrowDiff().update_growdiff({2014: {'_ABOOK': [-1.1]}}) - - def test_has_any_response(): start_year = GrowDiff.JSON_START_YEAR gdiff = GrowDiff() assert gdiff.current_year == start_year assert gdiff.has_any_response() is False - gdiff.update_growdiff({2020: {'_AWAGE': [0.01]}}) + gdiff.update_growdiff({'AWAGE': {2020: 0.01}}) assert gdiff.current_year == start_year assert gdiff.has_any_response() is True diff --git a/taxcalc/tests/test_parameters.py b/taxcalc/tests/test_parameters.py index 3119e49bf..75a7e5160 100644 --- a/taxcalc/tests/test_parameters.py +++ b/taxcalc/tests/test_parameters.py @@ -15,36 +15,155 @@ from taxcalc import Parameters, Policy, Consumption +# Test specification and use of simple Parameters-derived class that has +# no vector parameters and has no (wage or price) indexed parameters. +# This derived class is called Params and it contains one of each of the +# four types of parameters. +# +# The following pytest fixture specifies the JSON DEFAULTS file for the +# Params class, which is defined in the test_params_class function. + + +PARAMS_JSON = """ +{ +"real_param": { + "value_type": "real", + "value_yrs": [2001, 2002, 2003], + "value": [0.5, 0.5, 0.5], + "valid_values": {"min": 0, "max": 1} +}, +"int_param": { + "value_type": "integer", + "value_yrs": [2001, 2002, 2003], + "value": [2, 2, 2], + "valid_values": {"min": 0, "max": 9} +}, +"bool_param": { + "value_type": "boolean", + "value_yrs": [2001, 2002, 2003], + "value": [true, true, true], + "valid_values": {"min": false, "max": true} +}, +"str_param": { + "value_type": "string", + "value_yrs": [2001, 2002, 2003], + "value": ["linear", "linear", "linear"], + "valid_values": {"options": ["linear", "nonlinear", "cubic"]} +} +} +""" + + +@pytest.fixture(scope='module', name='params_json_file') +def fixture_params_json_file(): + """ + Define JSON DEFAULTS file for Parameters-derived Params class. + """ + with tempfile.NamedTemporaryFile(mode='a', delete=False) as pfile: + pfile.write(PARAMS_JSON + '\n') + pfile.close() + yield pfile + os.remove(pfile.name) + + +@pytest.mark.parametrize("revision, expect", [ + ({}, ""), + ({'real_param': {2004: 1.9}}, "error"), + ({'int_param': {2004: [3.6]}}, "raise"), + ({'bool_param': {2004: [4.9]}}, "raise"), + ({'str_param': {2004: [9]}}, "raise"), + ({'str_param': {2004: 'nonlinear'}}, "noerror"), + ({'str_param': {2004: 'unknownvalue'}}, "error"), + ({'str_param': {2004: ['nonlinear']}}, "raise"), + ({'real_param': {2004: 'linear'}}, "raise"), + ({'real_param-indexed': {2004: True}}, "raise"), + ({'unknown_param-indexed': {2004: False}}, "raise") +]) +def test_params_class(revision, expect, params_json_file): + """ + Specifies Params class and tests it. + """ + + class Params(Parameters): + """ + The Params class is derived from the abstract base Parameter class. + """ + DEFAULTS_FILE_NAME = params_json_file.name + DEFAULTS_FILE_PATH = '' + START_YEAR = 2001 + LAST_YEAR = 2010 + NUM_YEARS = LAST_YEAR - START_YEAR + 1 + + def __init__(self): + super().__init__() + self.initialize(Params.START_YEAR, Params.NUM_YEARS) + + def update_params(self, revision, + print_warnings=True, raise_errors=True): + """ + Update parameters given specified revision dictionary. + """ + self._update(revision, print_warnings, raise_errors) + + # test Params class + prms = Params() + if revision == {}: + assert isinstance(prms, Params) + assert prms.start_year == 2001 + assert prms.current_year == 2001 + assert prms.end_year == 2010 + assert prms.inflation_rates() is None + assert prms.wage_growth_rates() is None + prms.set_year(2010) + assert prms.current_year == 2010 + with pytest.raises(ValueError): + prms.set_year(2011) + return + if expect == 'raise': + with pytest.raises(ValueError): + prms.update_params(revision, + print_warnings=False, + raise_errors=False) + elif expect == 'noerror': + prms.update_params(revision, print_warnings=False, raise_errors=False) + assert not prms.parameter_errors + elif expect == 'error': + prms.update_params(revision, print_warnings=False, raise_errors=False) + assert prms.parameter_errors + elif expect == 'warn': + prms.update_params(revision, print_warnings=False, raise_errors=False) + assert prms.parameter_warnings + + @pytest.mark.parametrize("fname", [("consumption.json"), ("policy_current_law.json"), ("growdiff.json")]) def test_json_file_contents(tests_path, fname): """ - Check contents of JSON parameter files. + Check contents of JSON parameter files in Tax-Calculator/taxcalc directory. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements # specify test information required_keys = ['long_name', 'description', - 'section_1', 'section_2', 'notes', - 'row_label', - 'indexed', 'indexable', - 'col_var', 'col_label', - 'value_type', 'value', 'valid_values'] + 'value_type', 'value_yrs', 'value', 'valid_values'] valid_value_types = ['boolean', 'integer', 'real', 'string'] - invalid_keys = ['invalid_minmsg', 'invalid_maxmsg', 'invalid_action'] + if fname == 'policy_current_law.json': + invalid_keys = ['invalid_minmsg', 'invalid_maxmsg', 'invalid_action'] + else: + invalid_keys = [] first_year = Policy.JSON_START_YEAR last_known_year = Policy.LAST_KNOWN_YEAR # for indexed parameter values num_known_years = last_known_year - first_year + 1 - long_params = ['_II_brk1', '_II_brk2', '_II_brk3', '_II_brk4', - '_II_brk5', '_II_brk6', '_II_brk7', - '_PT_brk1', '_PT_brk2', '_PT_brk3', '_PT_brk4', - '_PT_brk5', '_PT_brk6', '_PT_brk7', - '_PT_excl_wagelim_thd', - '_ALD_BusinessLosses_c', - '_STD', '_II_em', - '_AMT_em', '_AMT_em_ps', '_AMT_em_pe', - '_ID_ps', '_ID_AllTaxes_c'] + long_params = ['II_brk1', 'II_brk2', 'II_brk3', 'II_brk4', + 'II_brk5', 'II_brk6', 'II_brk7', + 'PT_brk1', 'PT_brk2', 'PT_brk3', 'PT_brk4', + 'PT_brk5', 'PT_brk6', 'PT_brk7', + 'PT_excl_wagelim_thd', + 'ALD_BusinessLosses_c', + 'STD', 'II_em', + 'AMT_em', 'AMT_em_ps', 'AMT_em_pe', + 'ID_ps', 'ID_AllTaxes_c'] long_known_years = 2026 - first_year + 1 # for TCJA-reverting long_params # read JSON parameter file into a dictionary path = os.path.join(tests_path, '..', fname) @@ -60,10 +179,6 @@ def test_json_file_contents(tests_path, fname): # check that param contains required keys param = allparams[pname] assert isinstance(param, dict) - if 'indexable' not in param: - param['indexable'] = False - if 'indexed' not in param: - param['indexed'] = False for key in required_keys: assert key in param if param['value_type'] == 'string': @@ -73,7 +188,7 @@ def test_json_file_contents(tests_path, fname): else: for key in invalid_keys: assert key in param - assert param['invalid_action'] in ['stop', 'warn'] + assert param.get('invalid_action', 'stop') in ['stop', 'warn'] # check for non-empty long_name and description strings assert isinstance(param['long_name'], str) if not param['long_name']: @@ -82,16 +197,18 @@ def test_json_file_contents(tests_path, fname): if not param['description']: assert '{} description'.format(pname) == 'empty string' # check that indexable and indexed are boolean - assert isinstance(param['indexable'], bool) - assert isinstance(param['indexed'], bool) + assert isinstance(param.get('indexable', False), bool) + assert isinstance(param.get('indexed', False), bool) # check that indexable and indexed are False in many files if fname != 'policy_current_law.json': - assert param['indexable'] is False - assert param['indexed'] is False + assert param.get('indexable', False) is False + assert param.get('indexed', False) is False # check that indexable is True when indexed is True - if param['indexed'] and not param['indexable']: + if param.get('indexed', False) and not param.get('indexable', False): msg = 'param:<{}>; indexed={}; indexable={}' - fail = msg.format(pname, param['indexed'], param['indexable']) + fail = msg.format(pname, + param.get('indexed', False), + param.get('indexable', False)) failures += fail + '\n' # check that value_type is correct string if not param['value_type'] in valid_value_types: @@ -99,67 +216,69 @@ def test_json_file_contents(tests_path, fname): fail = msg.format(pname, param['value_type']) failures += fail + '\n' # check that indexable param has value_type real - if param['indexable'] and param['value_type'] != 'real': + if param.get('indexable', False) and param['value_type'] != 'real': msg = 'param:<{}>; value_type={}; indexable={}' fail = msg.format(pname, param['value_type'], - param['indexable']) + param.get('indexable', False)) failures += fail + '\n' # ensure that indexable is False when value_type is not real - if param['indexable'] and param['value_type'] != 'real': + if param.get('indexable', False) and param['value_type'] != 'real': msg = 'param:<{}>; indexable={}; value_type={}' - fail = msg.format(pname, param['indexable'], param['value_type']) + fail = msg.format(pname, + param.get('indexable', False), + param['value_type']) failures += fail + '\n' - # check that row_label is list - rowlabel = param['row_label'] - assert isinstance(rowlabel, list) - # check all row_label values + # check that value_yrs is list + valueyrs = param['value_yrs'] + assert isinstance(valueyrs, list) + # check all value_yrs values cyr = first_year - for rlabel in rowlabel: - assert int(rlabel) == cyr + for vyr in valueyrs: + assert vyr == cyr cyr += 1 # check type and dimension of value value = param['value'] assert isinstance(value, list) - assert len(value) == len(rowlabel) - # check that col_var and col_label are consistent - cvar = param['col_var'] - assert isinstance(cvar, str) - clab = param['col_label'] - if cvar == '': - assert isinstance(clab, str) and clab == '' + assert len(value) == len(valueyrs) + # check that vi_name and vi_vals are consistent + viname = param.get('vi_name', '') + assert isinstance(viname, str) + vivals = param.get('vi_vals', []) + if viname == '': + assert vivals == [] else: - assert isinstance(clab, list) - # check different possible col_var values - if cvar == 'MARS': - assert len(clab) == 5 - elif cvar == 'EIC': - assert len(clab) == 4 - elif cvar == 'idedtype': - assert len(clab) == 7 - elif cvar == 'c00100': + assert isinstance(vivals, list) + # check different possible vi_name values + if viname == 'MARS': + assert len(vivals) == 5 + elif viname == 'EIC': + assert len(vivals) == 4 + elif viname == 'idedtype': + assert len(vivals) == 7 + elif viname == 'c00100': pass else: - assert cvar == 'UNKNOWN col_var VALUE' + assert viname == 'UNKNOWN vi_name VALUE' # check length of each value row for valuerow in value: - assert len(valuerow) == len(clab) - # check that indexed parameters have all known years in rowlabel list - # form_parameters are those whose value is available only on IRS form + assert len(valuerow) == len(vivals) + # check that indexed parameters have all known years in value_yrs list + # (form_parameters are those whose value is available only on IRS form) form_parameters = [] - if param['indexed']: + if param.get('indexed', False): error = False known_years = num_known_years if pname in long_params: known_years = long_known_years if pname in form_parameters: - if len(rowlabel) != (known_years - 1): + if len(valueyrs) != (known_years - 1): error = True else: - if len(rowlabel) != known_years: + if len(valueyrs) != known_years: error = True if error: - msg = 'param:<{}>; len(rowlabel)={}; known_years={}' - fail = msg.format(pname, len(rowlabel), known_years) + msg = 'param:<{}>; len(value_yrs)={}; known_years={}' + fail = msg.format(pname, len(valueyrs), known_years) failures += fail + '\n' if failures: raise ValueError(failures) @@ -348,125 +467,3 @@ def test_bool_int_value_info(tests_path, json_filename): pdict[param]['value_type'], valstr) assert msg == 'ERROR: boolean_value param has non-boolean value' - - -@pytest.fixture(scope='module', name='params_defaults_json_file') -def fixture_defaultsjsonfile(): - """ - Define alternative JSON assumption parameter defaults file. - """ - json_text = """ -{ -"_int_param": { - "value_type": "integer", - "value": [2, 2, 2], - "valid_values": {"min": 0, "max": 9}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" -}, -"_bool_param": { - "value_type": "boolean", - "value": [true, true, true], - "valid_values": {"min": false, "max": true}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" -}, -"_str_param": { - "value_type": "string", - "value": ["linear", "linear", "linear"], - "valid_values": {"options": ["linear", "nonlinear", "cubic"]} -} -} -""" - with tempfile.NamedTemporaryFile(mode='a', delete=False) as pfile: - pfile.write(json_text + '\n') - pfile.close() - yield pfile - os.remove(pfile.name) - - -def test_alternative_defaults_file(params_defaults_json_file): - """ - Test Params class derived from Parameters base class. - """ - # pylint: disable=too-many-statements - class Params(Parameters): - """ - Params is derived from the Parameter class. - """ - DEFAULTS_FILE_NAME = params_defaults_json_file.name - DEFAULTS_FILE_PATH = '' - START_YEAR = 2001 - LAST_YEAR = 2099 - NUM_YEARS = LAST_YEAR - START_YEAR + 1 - - def __init__(self): - # read default parameters and initialize - super().__init__() - self.initialize(Params.START_YEAR, Params.NUM_YEARS) - # specify warning/error handling variables - self.parameter_errors = '' - self._ignore_errors = False - # end of Params class definition - - # test illegal instantiation of abstract Parameters class - with pytest.raises(AssertionError): - Parameters() - # test Params class derived from Parameters class - # ... (0) test call to wage_growth_rates method - prms = Params() - assert isinstance(prms, Params) - assert prms.start_year == 2001 - assert prms.current_year == 2001 - assert prms.wage_growth_rates() is None - del prms - # ... (1) test invalid set_year call - prms = Params() - with pytest.raises(ValueError): - prms.set_year(2100) - del prms - # ... (2) test a _validate_names_types error - prms = Params() - paramschange = {2014: {'_str_param': [9]}} - prms._validate_names_types(paramschange) - assert prms.parameter_errors - del prms - del paramschange - # ... (3) test a _validate_names_types error - prms = Params() - paramschange = {2014: {'_int_param': [3.6]}} - prms._validate_names_types(paramschange) - assert prms.parameter_errors - del prms - del paramschange - # ... (4) test a _validate_names_types error - prms = Params() - paramschange = {2014: {'_bool_param': [4.9]}} - prms._validate_names_types(paramschange) - assert prms.parameter_errors - del prms - del paramschange - # ... (5) test a valid change in string parameter value - prms = Params() - paramschange = {2014: {'_str_param': ['nonlinear']}} - prms.set_year(2014) - prms._update(paramschange) - changed_params = set() - changed_params.add('_str_param') - prms._validate_values(changed_params) - assert not prms.parameter_errors - del prms - del paramschange - # ... (6) test an invalid change in string parameter value - prms = Params() - paramschange = {2014: {'_str_param': ['unknownvalue']}} - prms.set_year(2014) - prms._update(paramschange) - changed_params = set() - changed_params.add('_str_param') - prms._validate_values(changed_params) - assert prms.parameter_errors - del prms - del paramschange diff --git a/taxcalc/tests/test_policy.py b/taxcalc/tests/test_policy.py index 5ee43f5f5..8365996dc 100644 --- a/taxcalc/tests/test_policy.py +++ b/taxcalc/tests/test_policy.py @@ -9,7 +9,6 @@ import os import json -import tempfile import numpy as np import pytest # pylint: disable=import-error @@ -34,31 +33,40 @@ def test_correct_class_instantiation(): with pytest.raises(ValueError): pol.implement_reform(list()) with pytest.raises(ValueError): - pol.implement_reform({2099: {'_II_em': [99000]}}) + pol.implement_reform({2099: {'II_em': 99000}}) pol.set_year(2019) with pytest.raises(ValueError): - pol.implement_reform({2018: {'_II_em': [99000]}}) + pol.implement_reform({2018: {'II_em': 99000}}) with pytest.raises(ValueError): - pol.implement_reform({2020: {'_II_em': [-1000]}}) + pol.implement_reform({2020: {'II_em': -1000}}) -def test_policy_json_content(): +def test_policy_json_content_consistency(): """ - Test contents of Policy object. + Test contents of JSON defaults file, which is read into Policy._vals dict. """ + expected_vi_vals = { + 'MARS': ['single', 'mjoint', 'marsep', 'headhh', 'widow'], + 'EIC': ['0kids', '1kid', '2kids', '3+kids'], + 'idedtype': ['med', 'sltx', 'retx', 'cas', 'misc', 'int', 'char'] + } policy = Policy() start_year = policy.start_year assert start_year == Policy.JSON_START_YEAR policy_vals = getattr(policy, '_vals') - for _, data in policy_vals.items(): - row_label = data.get('row_label') - assert isinstance(row_label, list) - value = data.get('value') - expected_row_label = [str(start_year + i) for i in range(len(value))] - if row_label != expected_row_label: - msg = 'name,row_label,expected_row_label: {}\n{}\n{}' - raise ValueError(msg.format(data.get('long_name')), row_label, - expected_row_label) + for name, data in policy_vals.items(): + # check entries in value_yrs list + value_yrs = data['value_yrs'] + assert isinstance(value_yrs, list) + value = data['value'] + expected_value_yrs = [(start_year + i) for i in range(len(value))] + if value_yrs != expected_value_yrs: + msg = 'name,value_yrs,expected_value_yrs: {}\n{}\n{}' + raise ValueError(msg.format(name, value_yrs, expected_value_yrs)) + # check entries in vi_vals list + vivals = data['vi_vals'] + if vivals: + assert set(vivals) == set(expected_vi_vals[data['vi_name']]) # pylint: disable=protected-access,no-member @@ -73,8 +81,8 @@ def test_constant_inflation_rate_with_reform(): fyr = Policy.LAST_BUDGET_YEAR ryr = fyr - 1 reform = { - (ryr - 3): {'_II_em': [1000]}, # to avoid divide-by-zero under TCJA - ryr: {'_II_em': [20000]} + 'II_em': {(ryr - 3): 1000, # to avoid divide-by-zero under TCJA + ryr: 20000} } pol.implement_reform(reform) # extract price inflation rates @@ -99,8 +107,8 @@ def test_variable_inflation_rate_with_reform(): assert pol._II_em[2013 - syr] == 3900 # implement reform in 2020 which is two years before the last year, 2022 reform = { - 2018: {'_II_em': [1000]}, # to avoid divide-by-zero under TCJA - 2020: {'_II_em': [20000]} + 'II_em': {2018: 1000, # to avoid divide-by-zero under TCJA + 2020: 20000} } pol.implement_reform(reform) pol.set_year(2020) @@ -181,31 +189,25 @@ def test_multi_year_reform(): inflation_rates=wratelist, num_years=nyrs), atol=0.01, rtol=0.0) - # specify multi-year reform using a dictionary of year_provisions dicts + # specify multi-year reform using a param:year:value-fomatted dictionary reform = { - 2015: { - '_CTC_c': [2000] - }, - 2016: { - '_EITC_c': [[900, 5000, 8000, 9000]], - '_II_em': [7000], - '_SS_Earnings_c': [300000] - }, - 2017: { - '_SS_Earnings_c': [500000], '_SS_Earnings_c_cpi': False - }, - 2019: { - '_EITC_c': [[1200, 7000, 10000, 12000]], - '_II_em': [9000], - '_SS_Earnings_c': [700000], '_SS_Earnings_c_cpi': True - } + 'SS_Earnings_c': {2016: 300000, + 2017: 500000, + 2019: 700000}, + 'SS_Earnings_c-indexed': {2017: False, + 2019: True}, + 'CTC_c': {2015: 2000}, + 'EITC_c': {2016: [900, 5000, 8000, 9000], + 2019: [1200, 7000, 10000, 12000]}, + 'II_em': {2016: 7000, + 2019: 9000} } # implement multi-year reform pol.implement_reform(reform) assert pol.current_year == syr # move policy Policy object forward in time so current_year is syr+2 # Note: this would be typical usage because the first budget year - # is greater than Policy start_year. + # is typically greater than Policy start_year. pol.set_year(pol.start_year + 2) assert pol.current_year == syr + 2 # confirm that actual parameters have expected post-reform values @@ -229,7 +231,7 @@ def check_ctc_c(ppo, reform): actual[ppo.start_year + i] = arr[i] assert actual[2013] == 1000 assert actual[2014] == 1000 - e2015 = reform[2015]['_CTC_c'][0] + e2015 = reform['CTC_c'][2015] assert actual[2015] == e2015 e2016 = actual[2015] assert actual[2016] == e2016 @@ -257,13 +259,13 @@ def check_eitc_c(ppo, reform, ifactor): atol=0.01, rtol=0.0) assert np.allclose(actual[2015], [503, 3359, 5548, 6242], atol=0.01, rtol=0.0) - e2016 = reform[2016]['_EITC_c'][0] + e2016 = reform['EITC_c'][2016] assert np.allclose(actual[2016], e2016, atol=0.01, rtol=0.0) e2017 = [ifactor[2016] * actual[2016][j] for j in range(0, alen)] assert np.allclose(actual[2017], e2017, atol=0.01, rtol=0.0) e2018 = [ifactor[2017] * actual[2017][j] for j in range(0, alen)] assert np.allclose(actual[2018], e2018, atol=0.01, rtol=0.0) - e2019 = reform[2019]['_EITC_c'][0] + e2019 = reform['EITC_c'][2019] assert np.allclose(actual[2019], e2019, atol=0.01, rtol=0.0) e2020 = [ifactor[2019] * actual[2019][j] for j in range(0, alen)] assert np.allclose(actual[2020], e2020, atol=0.01, rtol=0.0) @@ -285,13 +287,13 @@ def check_ii_em(ppo, reform, ifactor): assert actual[2013] == 3900 assert actual[2014] == 3950 assert actual[2015] == 4000 - e2016 = reform[2016]['_II_em'][0] + e2016 = reform['II_em'][2016] assert actual[2016] == e2016 e2017 = ifactor[2016] * actual[2016] assert np.allclose([actual[2017]], [e2017], atol=0.01, rtol=0.0) e2018 = ifactor[2017] * actual[2017] assert np.allclose([actual[2018]], [e2018], atol=0.01, rtol=0.0) - e2019 = reform[2019]['_II_em'][0] + e2019 = reform['II_em'][2019] assert actual[2019] == e2019 e2020 = ifactor[2019] * actual[2019] assert np.allclose([actual[2020]], [e2020], atol=0.01, rtol=0.0) @@ -313,13 +315,13 @@ def check_ss_earnings_c(ppo, reform, wfactor): assert actual[2013] == 113700 assert actual[2014] == 117000 assert actual[2015] == 118500 - e2016 = reform[2016]['_SS_Earnings_c'][0] + e2016 = reform['SS_Earnings_c'][2016] assert actual[2016] == e2016 - e2017 = reform[2017]['_SS_Earnings_c'][0] + e2017 = reform['SS_Earnings_c'][2017] assert actual[2017] == e2017 e2018 = actual[2017] # no indexing after 2017 assert actual[2018] == e2018 - e2019 = reform[2019]['_SS_Earnings_c'][0] + e2019 = reform['SS_Earnings_c'][2019] assert actual[2019] == e2019 e2020 = wfactor[2019] * actual[2019] # indexing after 2019 assert actual[2020] == e2020 @@ -329,125 +331,62 @@ def check_ss_earnings_c(ppo, reform, wfactor): assert np.allclose([actual[2022]], [e2022], atol=0.01, rtol=0.0) -@pytest.fixture(scope='module', name='defaults_json_file') -def fixture_defaultsjsonfile(): - """ - Define alternative JSON policy parameter defaults file. - """ - # specify JSON text for alternative to policy_current_law.json file - json_text = """ -{ -"_param1": { - "value_type": "real", - "value": [5000, 6000, 7000], - "valid_values": {"min": 0, "max": 9e99}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" -}, -"_param2": { - "value_type": "integer", - "value": [2, 2, 2], - "valid_values": {"min": 0, "max": 9}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" -}, -"_param3": { - "value_type": "boolean", - "value": [true, true, true], - "valid_values": {"min": false, "max": true}, - "invalid_minmsg": "", - "invalid_maxmsg": "", - "invalid_action": "stop" -}, -"_param4": { - "value_type": "string", - "value": ["linear", "linear", "linear"], - "valid_values": {"options": ["linear", "nonlinear", "cubic"]} -} -} -""" - with tempfile.NamedTemporaryFile(mode='a', delete=False) as pfile: - pfile.write(json_text + '\n') - pfile.close() - yield pfile - os.remove(pfile.name) - - def test_policy_metadata(): """ Test that metadata() method returns expected dictionary. """ clp = Policy() mdata = clp.metadata() - assert mdata['_CDCC_ps']['value'] == [15000] + assert isinstance(mdata['STD']['value'], list) + assert np.allclose(mdata['STD']['value'], + [6100, 12200, 6100, 8950, 12200]) + assert isinstance(mdata['CDCC_ps']['value'], float) + assert mdata['CDCC_ps']['value'] == 15000 + dump = False + if dump: + print(mdata) + assert 1 == 2 def test_implement_reform_raises_on_no_year(): """ Test that implement_reform raises error for missing year. """ - reform = {'_STD_Aged': [[1400, 1200]]} + reform = {'STD_Aged': [1400, 1200, 1400, 1400, 1400]} ppo = Policy() with pytest.raises(ValueError): ppo.implement_reform(reform) -def test_reform_in_start_year(): - """ - Test that implement_reform handles multiple-year reform. - """ - ppo = Policy() - reform = {2013: {'_STD': [[16000, 13000, 13000, 16000, 16000]]}} - ppo.implement_reform(reform) - assert np.allclose(ppo.STD, - np.array([16000, 13000, 13000, 16000, 16000]), - atol=0.01, rtol=0.0) - - def test_implement_reform_raises_on_early_year(): """ Test that implement_reform raises error for early year. """ ppo = Policy() - reform = {2010: {'_STD_Aged': [[1400, 1100, 1100, 1400, 1400]]}} + reform = {'STD_Aged': {2010: [1400, 1100, 1100, 1400, 1400]}} with pytest.raises(ValueError): ppo.implement_reform(reform) -def test_reform_with_default_cpi_flags(): +def test_reform_with_default_indexed(): """ Test that implement_reform indexes after first reform year. """ ppo = Policy() - reform = {2015: {'_II_em': [4300]}} + reform = {'II_em': {2015: 4300}} ppo.implement_reform(reform) - # '_II_em' has a default cpi_flag of True, so + # II_em has a default indexing status of true, so # in 2016 its value should be greater than 4300 ppo.set_year(2016) assert ppo.II_em > 4300 -def test_reform_after_start_year(): - """ - Test that implement_reform makes changes in years after first reform year. - """ - ppo = Policy() - reform = {2015: {'_STD_Aged': [[1400, 1100, 1100, 1400, 1400]]}} - ppo.implement_reform(reform) - ppo.set_year(2015) - assert np.allclose(ppo.STD_Aged, - np.array([1400, 1100, 1100, 1400, 1400]), - atol=0.01, rtol=0.0) - - def test_reform_makes_no_changes_before_year(): """ Test that implement_reform makes no changes before first reform year. """ ppo = Policy() - reform = {2015: {'_II_em': [4400], '_II_em_cpi': True}} + reform = {'II_em': {2015: 4400}, 'II_em-indexed': {2015: True}} ppo.implement_reform(reform) ppo.set_year(2015) assert np.allclose(ppo._II_em[:3], np.array([3900, 3950, 4400]), @@ -474,29 +413,29 @@ def test_read_json_param_and_implement_reform(set_year): // lowercase characters. { "policy": { - "_AMT_brk1": // top of first AMT tax bracket - {"2015": [200000], - "2017": [300000] + "AMT_brk1": // top of first AMT tax bracket + {"2015": 200000, + "2017": 300000 }, - "_EITC_c": // max EITC amount by number of qualifying kids (0,1,2,3+) - {"2016": [[ 900, 5000, 8000, 9000]], - "2019": [[1200, 7000, 10000, 12000]] + "EITC_c": // max EITC amount by number of qualifying kids (0,1,2,3+) + {"2016": [ 900, 5000, 8000, 9000], + "2019": [1200, 7000, 10000, 12000] }, - "_II_em": // personal exemption amount (see indexing changes below) - {"2016": [6000], - "2018": [7500], - "2020": [9000] + "II_em": // personal exemption amount (see indexing changes below) + {"2016": 6000, + "2018": 7500, + "2020": 9000 }, - "_II_em_cpi": // personal exemption amount indexing status + "II_em-indexed": // personal exemption amount indexing status {"2016": false, // values in future years are same as this year value "2018": true // vals in future years indexed with this year as base }, - "_SS_Earnings_c": // Social Security (OASDI) maximum taxable earnings - {"2016": [300000], - "2018": [500000], - "2020": [700000] + "SS_Earnings_c": // Social Security (OASDI) maximum taxable earnings + {"2016": 300000, + "2018": 500000, + "2020": 700000 }, - "_AMT_em_cpi": // AMT exemption amount indexing status + "AMT_em-indexed": // AMT exemption amount indexing status {"2017": false, // values in future years are same as this year value "2020": true // vals in future years indexed with this year as base } @@ -550,30 +489,36 @@ def test_pop_the_cap_reform(): assert mte[2015 - syr] == 118500 assert mte[2016 - syr] == 118500 # specify a "pop the cap" reform that eliminates MTE cap in 2016 - reform = {2016: {'_SS_Earnings_c': [9e99]}} + reform = {'SS_Earnings_c': {2016: 9e99}} ppo.implement_reform(reform) assert mte[2015 - syr] == 118500 assert mte[2016 - syr] == 9e99 assert mte[ppo.end_year - syr] == 9e99 -def test_order_of_cpi_and_level_reforms(): +def test_order_of_indexing_and_level_reforms(): """ Test that the order of the two reform provisions for the same parameter make no difference to the post-reform policy parameter values. """ # specify two reforms that raises the MTE and stops its indexing in 2015 - reform = [{2015: {'_SS_Earnings_c': [500000], - '_SS_Earnings_c_cpi': False}}, - # now reverse the order of the two reform provisions - {2015: {'_SS_Earnings_c_cpi': False, - '_SS_Earnings_c': [500000]}}] + reform = [ + { + 'SS_Earnings_c': {2015: 500000}, + 'SS_Earnings_c-indexed': {2015: False} + }, + # now reverse the order of the two reform provisions + { + 'SS_Earnings_c-indexed': {2015: False}, + 'SS_Earnings_c': {2015: 500000} + } + ] # specify two Policy objects ppo = [Policy(), Policy()] # apply reforms to corresponding Policy object & check post-reform values syr = Policy.JSON_START_YEAR for ref in range(len(reform)): # pylint: disable=consider-using-enumerate - # confirm pre-reform MTE values in 2014-17 + # confirm pre-reform MTE values in 2014-2017 mte = ppo[ref]._SS_Earnings_c assert mte[2014 - syr] == 117000 assert mte[2015 - syr] == 118500 @@ -581,7 +526,7 @@ def test_order_of_cpi_and_level_reforms(): assert mte[2017 - syr] < 500000 # implement reform in 2015 ppo[ref].implement_reform(reform[ref]) - # confirm post-reform MTE values in 2014-17 + # confirm post-reform MTE values in 2014-2017 mte = ppo[ref]._SS_Earnings_c assert mte[2014 - syr] == 117000 assert mte[2015 - syr] == 500000 @@ -589,20 +534,19 @@ def test_order_of_cpi_and_level_reforms(): assert mte[2017 - syr] == 500000 -def test_misspecified_reforms(): +def test_misspecified_reform_dictionary(): """ - Demonstrate pitfalls of careless specification of policy reforms. + Demonstrate pitfalls of careless specification of policy reform + dictionaries involving non-unique dictionary keys. """ # specify apparently the same reform in two different ways, forgetting # that Python dictionaries have unique keys - reform1 = {2016: {'_SS_Earnings_c': [500000], - '_II_em': [9000]}} + reform1 = {'II_em': {2019: 1000, 2020: 2000}} # pylint: disable=duplicate-key - reform2 = {2016: {'_SS_Earnings_c': [500000]}, - 2016: {'_II_em': [9000]}} + reform2 = {'II_em': {2019: 1000}, 'II_em': {2020: 2000}} # these two reform dictionaries are not the same: the second - # 2016 key:value pair in reform2 (2016:{'_II_em...}) overwrites and - # replaces the first 2016 key:value pair in reform2 (2016:{'_SS_E...}) + # 'II_em' key value for 2020 in reform2 OVERWRITES and REPLACES + # the first 'II_em' key value for 2019 in reform2 assert reform1 != reform2 @@ -790,23 +734,19 @@ def test_description_punctuation(tests_path): assert all_desc_ok -def test_valid_value_infomation(tests_path): +def test_valid_value_infomation(): """ Check consistency of valid_values info in policy_current_law.json file. """ # pylint: disable=too-many-statements,too-many-locals # pylint: disable=too-many-branches,too-many-nested-blocks - # read policy_current_law.json file into a dictionary - path = os.path.join(tests_path, '..', 'policy_current_law.json') - with open(path, 'r') as clpfile: - clpdict = json.load(clpfile) - parameters = set(clpdict.keys()) - # construct set of parameter names with "valid_values" field in clpdict + # construct set of parameter names with a "valid_values" field + policy = Policy() min_max_list = ['min', 'max'] warn_stop_list = ['warn', 'stop'] json_range_params = set() - for pname in parameters: - param = clpdict[pname] + parameters = set(policy._vals.keys()) + for pname, param in policy._vals.items(): assert isinstance(param, dict) if param['value_type'] == 'string': continue # because string parameters have no invalid_* keys @@ -825,14 +765,16 @@ def test_valid_value_infomation(tests_path): msg = 'USES DEFAULT FOR min OR FOR error' assert pname == msg continue - elif vval in clpdict: - if vop == 'min': - extra_msg = param['invalid_minmsg'] - if vop == 'max': - extra_msg = param['invalid_maxmsg'] - assert vval in extra_msg else: - assert vval == 'ILLEGAL RANGE STRING VALUE' + vval_ = '_' + vval + if vval_ in parameters: + if vop == 'min': + extra_msg = param['invalid_minmsg'] + if vop == 'max': + extra_msg = param['invalid_maxmsg'] + assert vval in extra_msg + else: + assert vval == 'ILLEGAL RANGE STRING VALUE' else: # if vval is not a str if isinstance(vval, int): continue @@ -848,145 +790,79 @@ def test_valid_value_infomation(tests_path): assert unmatched == 'UNMATCHED RANGE PARAMETERS' # check all current-law-policy parameters for range validity clp = Policy() - redefined = { - '_CTC_c': '_CTC_c was redefined in release 1.0.0 (2019-Q1)' - } - clp._validate_values(parameters, redefined_info=redefined) + clp._validate_values(parameters) # eventually activate: assert not clp.parameter_warnings - ctc_c_warning = '_CTC_c was redefined in release 1.0.0 (2019-Q1)\n' + ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n' assert clp.parameter_warnings == ctc_c_warning assert not clp.parameter_errors -def test_validate_param_names_types_errors(): +def test_indexing_rates_for_update(): """ - Check detection of invalid policy parameter names and types in reforms. + Check private _indexing_rates_for_update method. """ - # pylint: disable=too-many-statements - pol = Policy() - ref = {2020: {'_STD_cpi': 2}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - pol = Policy() - ref = {2020: {'_badname_cpi': True}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol pol = Policy() - ref = {2020: {'_II_em_cpi': 5}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - pol = Policy() - ref = {2020: {'_badname': [0.4]}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - pol = Policy() - ref = {2020: {'_EITC_MinEligAge': [21.4]}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - pol = Policy() - ref = {2025: {'_ID_BenefitSurtax_Switch': [[False, True, 0, 1, 0, 1, 0]]}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - pol = Policy() - ref = {2021: {'_II_em': ['not-a-number']}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - pol = Policy() - ref = {2019: {'_FICA_ss_trt_cpi': True}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - # this test was contributed by Hank Doupe in bug report #1956 - pol = Policy() - ref = {2019: {'_AMEDT_rt': [True]}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - # this test extends the prior test to integer parameters - pol = Policy() - ref = {2019: {'_AMT_KT_c_Age': [True]}} - with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - # this test checks "is a removed parameter" error for base parameter + wgrates = pol._indexing_rates_for_update('_SS_Earnings_c', 2017, 10) + pirates = pol._indexing_rates_for_update('_II_em', 2017, 10) + assert len(wgrates) == len(pirates) + + +def test_reform_with_bad_ctc_levels(): + """ + Implement a reform with _ACTC > _CTC_c values. + """ pol = Policy() - ref = {2019: {'_DependentCredit_Child_c': [400]}} + child_credit_reform = { + 'CTC_c': {2020: 2200}, + 'ACTC_c': {2020: 2500} + } with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - # this test checks "is a removed parameter" error for _cpi parameter - pol = Policy() - ref = {2019: {'_DependentCredit_Child_c_cpi': False}} + pol.implement_reform(child_credit_reform) + + +def test_reform_with_removed_parameter(): + """ + Try to use removed parameter in a reform. + """ + policy1 = Policy() + reform1 = {'FilerCredit_c': {2020: 1000}} with pytest.raises(ValueError): - pol.implement_reform(ref) - del pol - - -def test_validate_param_values_warnings_errors(): - """ - Check detection of out_of_range policy parameters in reforms. - """ - pol1 = Policy() - ref1 = {2020: {'_ID_Medical_frt': [0.05]}} - pol1.implement_reform(ref1, print_warnings=True, raise_errors=False) - assert pol1.parameter_warnings - pol2 = Policy() - ref2 = {2021: {'_ID_Charity_crt_all': [0.61]}} - pol2.implement_reform(ref2, print_warnings=False, raise_errors=False) - assert pol2.parameter_warnings - pol3 = Policy() - ref3 = {2024: {'_II_brk4': [[0, 0, 0, 0, 0]]}} - pol3.implement_reform(ref3, print_warnings=False, raise_errors=False) - assert pol3.parameter_errors - pol4 = Policy() - ref4 = {2024: {'_II_brk4': [[0, 9e9, 0, 0, 0]]}} - pol4.implement_reform(ref4, print_warnings=False, raise_errors=False) - assert pol4.parameter_errors - pol5 = Policy() - ref5 = {2025: {'_ID_BenefitSurtax_Switch': [[False, True, 0, 1, 0, 1, 0]]}} + policy1.implement_reform(reform1) + policy2 = Policy() + reform2 = {'FilerCredit_c-indexed': {2020: True}} with pytest.raises(ValueError): - pol5.implement_reform(ref5, print_warnings=False, raise_errors=False) - pol6 = Policy() - ref6 = {2013: {'_STD': [[20000, 25000, 20000, 20000, 25000]]}} - pol6.implement_reform(ref6, print_warnings=False, raise_errors=False) - assert pol6.parameter_errors == '' - assert pol6.parameter_warnings == '' + policy2.implement_reform(reform2) -def test_indexing_rates_for_update(): +def test_reform_with_out_of_range_error(): """ - Check private _indexing_rates_for_update method. + Try to use out-of-range values versus other parameter values in a reform. """ pol = Policy() - wgrates = pol._indexing_rates_for_update('_SS_Earnings_c', 2017, 10) - pirates = pol._indexing_rates_for_update('_II_em', 2017, 10) - assert len(wgrates) == len(pirates) + reform = {'SS_thd85': {2020: [20000, 20000, 20000, 20000, 20000]}} + pol.implement_reform(reform, raise_errors=False) + assert pol.parameter_errors -def test_reform_with_cpi_offset(): +def test_reform_with_warning(): """ - Implement a reform that includes the _cpi_offset policy parameter. + Try to use warned out-of-range parameter value in reform. """ - indexing_reform = {2020: {'_cpi_offset': [-0.0025]}} - pol = Policy() # current-law policy - pol.implement_reform(indexing_reform) - assert not pol.parameter_errors + pol = Policy() + reform = {'ID_Medical_frt': {2020: 0.05}} + pol.implement_reform(reform) + assert pol.parameter_warnings -def test_reform_with_bad_ctc_levels(): +def test_reform_with_scalar_vector_errors(): """ - Implement a reform with _ACTC > _CTC_c values. + Test catching scalar-vector confusion. """ - child_credit_reform = { - 2020: {'_CTC_c': [2200], '_ACTC_c': [2500]} - } - pol = Policy() + policy1 = Policy() + reform1 = {'SS_thd85': {2020: 30000}} with pytest.raises(ValueError): - pol.implement_reform(child_credit_reform) + policy1.implement_reform(reform1) + policy2 = Policy() + reform2 = {'ID_Medical_frt': {2020: [0.08]}} + with pytest.raises(ValueError): + policy2.implement_reform(reform2) diff --git a/taxcalc/tests/test_pufcsv.py b/taxcalc/tests/test_pufcsv.py index 2d9898767..496b0fa3c 100644 --- a/taxcalc/tests/test_pufcsv.py +++ b/taxcalc/tests/test_pufcsv.py @@ -291,7 +291,7 @@ def test_mtr_pt_active(puf_subsample): assert min(mtr1_e00900p) > -1 assert min(mtr1_e26270) > -1 # change PT rates, calc2 - reform2 = {reform_year: {'_PT_rt7': [0.35]}} + reform2 = {'PT_rt7': {reform_year: 0.35}} pol2 = Policy() pol2.implement_reform(reform2) calc2 = Calculator(policy=pol2, records=rec) @@ -302,7 +302,7 @@ def test_mtr_pt_active(puf_subsample): assert min(mtr2_e00900p) > -1 assert min(mtr2_e26270) > -1 # change PT_wages_active_income - reform3 = {reform_year: {'_PT_wages_active_income': [True]}} + reform3 = {'PT_wages_active_income': {reform_year: True}} pol3 = Policy() pol3.implement_reform(reform3) calc3 = Calculator(policy=pol3, records=rec) @@ -313,8 +313,10 @@ def test_mtr_pt_active(puf_subsample): assert min(mtr3_e00900p) > -1 assert min(mtr3_e26270) > -1 # change PT rates and PT_wages_active_income - reform4 = {reform_year: {'_PT_wages_active_income': [True], - '_PT_rt7': [0.35]}} + reform4 = { + 'PT_wages_active_income': {reform_year: True}, + 'PT_rt7': {reform_year: 0.35} + } pol4 = Policy() pol4.implement_reform(reform4) calc4 = Calculator(policy=pol4, records=rec) @@ -340,14 +342,14 @@ def test_credit_reforms(puf_subsample): calc1.calc_all() itax1 = calc1.weighted_total('iitax') # create personal-refundable-credit-reform Calculator object, calc2 - reform = {reform_year: {'_II_credit': [[1000, 1000, 1000, 1000, 1000]]}} + reform = {'II_credit': {reform_year: [1000, 1000, 1000, 1000, 1000]}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.advance_to_year(reform_year) calc2.calc_all() itax2 = calc2.weighted_total('iitax') # create personal-nonrefundable-credit-reform Calculator object, calc3 - reform = {reform_year: {'_II_credit_nr': [[1000, 1000, 1000, 1000, 1000]]}} + reform = {'II_credit_nr': {reform_year: [1000, 1000, 1000, 1000, 1000]}} pol = Policy() pol.implement_reform(reform) calc3 = Calculator(policy=pol, records=rec) diff --git a/taxcalc/tests/test_reforms.py b/taxcalc/tests/test_reforms.py index f12d5d956..ebab1bcd2 100644 --- a/taxcalc/tests/test_reforms.py +++ b/taxcalc/tests/test_reforms.py @@ -29,7 +29,7 @@ def test_2017_law_reform(tests_path): reform = Calculator.read_json_param_objects(rtext, None) pol.implement_reform(reform['policy']) # eventually activate: assert not clp.parameter_warnings - ctc_c_warning = '_CTC_c was redefined in release 1.0.0 (2019-02-22)\n' + ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n' assert pol.parameter_warnings == ctc_c_warning assert not pol.parameter_errors pol.set_year(2018) @@ -39,32 +39,32 @@ def test_2017_law_reform(tests_path): # relation '<' implies asserting that actual < expect # relation '>' implies asserting that actual > expect # ... parameters not affected by TCJA and that are not indexed - '_AMEDT_ec': {'relation': '=', 'value': 200000}, - '_SS_thd85': {'relation': '=', 'value': 34000}, + 'AMEDT_ec': {'relation': '=', 'value': 200000}, + 'SS_thd85': {'relation': '=', 'value': 34000}, # ... parameters not affected by TCJA and that are indexed - '_STD_Dep': {'relation': '>', 'value': 1050}, - '_CG_brk2': {'relation': '>', 'value': 425800}, - '_AMT_CG_brk1': {'relation': '>', 'value': 38600}, - '_AMT_brk1': {'relation': '>', 'value': 191100}, - '_EITC_c': {'relation': '>', 'value': 519}, - '_EITC_ps': {'relation': '>', 'value': 8490}, - '_EITC_ps_MarriedJ': {'relation': '>', 'value': 5680}, - '_EITC_InvestIncome_c': {'relation': '>', 'value': 3500}, + 'STD_Dep': {'relation': '>', 'value': 1050}, + 'CG_brk2': {'relation': '>', 'value': 425800}, + 'AMT_CG_brk1': {'relation': '>', 'value': 38600}, + 'AMT_brk1': {'relation': '>', 'value': 191100}, + 'EITC_c': {'relation': '>', 'value': 519}, + 'EITC_ps': {'relation': '>', 'value': 8490}, + 'EITC_ps_MarriedJ': {'relation': '>', 'value': 5680}, + 'EITC_InvestIncome_c': {'relation': '>', 'value': 3500}, # ... parameters affected by TCJA and that are not indexed - '_ID_Charity_crt_all': {'relation': '=', 'value': 0.5}, - '_II_rt3': {'relation': '=', 'value': 0.25}, + 'ID_Charity_crt_all': {'relation': '=', 'value': 0.5}, + 'II_rt3': {'relation': '=', 'value': 0.25}, # ... parameters affected by TCJA and that are indexed - '_II_brk3': {'relation': '>', 'value': 91900}, - '_STD': {'relation': '<', 'value': 7000}, - '_II_em': {'relation': '>', 'value': 4050}, - '_AMT_em_pe': {'relation': '<', 'value': 260000} + 'II_brk3': {'relation': '>', 'value': 91900}, + 'STD': {'relation': '<', 'value': 7000}, + 'II_em': {'relation': '>', 'value': 4050}, + 'AMT_em_pe': {'relation': '<', 'value': 260000} } assert isinstance(pre_expect, dict) assert set(pre_expect.keys()).issubset(set(pre_mdata.keys())) for name in pre_expect: - aval = pre_mdata[name]['value'][0] + aval = pre_mdata[name]['value'] if isinstance(aval, list): - act = aval[0] # comparing only first item in a nonscalar parameter + act = aval[0] # comparing only first item in a vector parameter else: act = aval exp = pre_expect[name]['value'] @@ -101,7 +101,7 @@ def test_round_trip_tcja_reform(tests_path): reform = Calculator.read_json_param_objects(rtext, None) pol.implement_reform(reform['policy']) # eventually activate: assert not clp.parameter_warnings - ctc_c_warning = '_CTC_c was redefined in release 1.0.0 (2019-02-22)\n' + ctc_c_warning = 'CTC_c was redefined in release 1.0.0\n' assert pol.parameter_warnings == ctc_c_warning assert not pol.parameter_errors reform_file = os.path.join(tests_path, '..', 'reforms', 'TCJA.json') @@ -257,7 +257,9 @@ def reform_results(rid, reform_dict, puf_data, reform_2017_law): calc1 = Calculator(policy=pol, records=rec, verbose=False) # create reform Calculator object, calc2 start_year = reform_dict['start_year'] - reform = {start_year: reform_dict['value']} + reform = dict() + for name, value in reform_dict['value'].items(): + reform[name] = {start_year: value} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec, verbose=False) # increment both Calculator objects to reform's start_year diff --git a/taxcalc/tests/test_taxcalcio.py b/taxcalc/tests/test_taxcalcio.py index e99e2fffe..bb36e1c14 100644 --- a/taxcalc/tests/test_taxcalcio.py +++ b/taxcalc/tests/test_taxcalcio.py @@ -31,9 +31,9 @@ def fixture_reformfile0(): """ txt = """ { "policy": { - "_SS_Earnings_c": {"2016": [300000], - "2018": [500000], - "2020": [700000]} + "SS_Earnings_c": {"2016": 300000, + "2018": 500000, + "2020": 700000} } } """ @@ -57,7 +57,7 @@ def fixture_assumpfile0(): contents = """ { "consumption": {}, - "growdiff_baseline": {"_ABOOK": {"2015": [-0.01]}}, + "growdiff_baseline": {"ABOOK": {"2015": -0.01}}, "growdiff_response": {} } """ @@ -79,25 +79,25 @@ def fixture_reformfile1(): rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) contents = """ {"policy": { - "_AMT_brk1": { // top of first AMT tax bracket - "2015": [200000], - "2017": [300000]}, - "_EITC_c": { // max EITC amount by number of qualifying kids (0,1,2,3+) - "2016": [[ 900, 5000, 8000, 9000]], - "2019": [[1200, 7000, 10000, 12000]]}, - "_II_em": { // personal exemption amount (see indexing changes below) - "2016": [6000], - "2018": [7500], - "2020": [9000]}, - "_II_em_cpi": { // personal exemption amount indexing status + "AMT_brk1": { // top of first AMT tax bracket + "2015": 200000, + "2017": 300000}, + "EITC_c": { // max EITC amount by number of qualifying kids (0,1,2,3+) + "2016": [ 900, 5000, 8000, 9000], + "2019": [1200, 7000, 10000, 12000]}, + "II_em": { // personal exemption amount (see indexing changes below) + "2016": 6000, + "2018": 7500, + "2020": 9000}, + "II_em-indexed": { // personal exemption amount indexing status "2016": false, // values in future years are same as this year value "2018": true // values in future years indexed with this year as base }, - "_SS_Earnings_c": { // social security (OASDI) maximum taxable earnings - "2016": [300000], - "2018": [500000], - "2020": [700000]}, - "_AMT_em_cpi": { // AMT exemption amount indexing status + "SS_Earnings_c": { // social security (OASDI) maximum taxable earnings + "2016": 300000, + "2018": 500000, + "2020": 700000}, + "AMT_em-indexed": { // AMT exemption amount indexing status "2017": false, // values in future years are same as this year value "2020": true // values in future years indexed with this year as base } @@ -120,7 +120,7 @@ def fixture_baselinebad(): Temporary baseline file with .json extension. """ rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) - contents = '{ "policy": {"_AMT_brk1": {"2011": [0.0]}}}' + contents = '{ "policy": {"AMT_brk1": {"2011": 0.0}}}' rfile.write(contents) rfile.close() yield rfile @@ -137,7 +137,7 @@ def fixture_errorreformfile(): Temporary reform file with .json extension. """ rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) - contents = '{ "policy": {"_xxx": {"2015": [0]}}}' + contents = '{ "policy": {"xxx": {"2015": 0}}}' rfile.write(contents) rfile.close() yield rfile @@ -156,9 +156,9 @@ def fixture_errorassumpfile(): rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) contents = """ { - "consumption": {"_MPC_e18400": {"2018": [-9]}}, - "growdiff_baseline": {"_ABOOKxx": {"2017": [0.02]}}, - "growdiff_response": {"_ABOOKxx": {"2017": [0.02]}} + "consumption": {"MPC_e18400": {"2018": -9}}, + "growdiff_baseline": {"ABOOKxx": {"2017": 0.02}}, + "growdiff_response": {"ABOOKxx": {"2017": 0.02}} } """ rfile.write(contents) @@ -179,7 +179,7 @@ def fixture_assumpfile1(): afile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) contents = """ { - "consumption": { "_MPC_e18400": {"2018": [0.05]} }, + "consumption": { "MPC_e18400": {"2018": 0.05} }, "growdiff_baseline": {}, "growdiff_response": {} } @@ -200,7 +200,7 @@ def fixture_lumpsumreformfile(): Temporary reform file without .json extension. """ rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) - lumpsum_reform_contents = '{"policy": {"_LST": {"2013": [200]}}}' + lumpsum_reform_contents = '{"policy": {"LST": {"2013": 200}}}' rfile.write(lumpsum_reform_contents) rfile.close() yield rfile @@ -219,7 +219,7 @@ def fixture_assumpfile2(): afile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) assump2_contents = """ { - "consumption": {"_BEN_snap_value": {"2018": [0.90]}}, + "consumption": {"BEN_snap_value": {"2018": 0.90}}, "growdiff_baseline": {}, "growdiff_response": {} } @@ -650,7 +650,7 @@ def fixture_warnreformfile(): Temporary reform file with .json extension. """ rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) - contents = '{"policy": {"_STD_Dep": {"2015": [0]}}}' + contents = '{"policy": {"STD_Dep": {"2015": 0}}}' rfile.write(contents) rfile.close() yield rfile @@ -694,10 +694,10 @@ def fixture_reformfile9(): rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False) contents = """ { "policy": { - "_SS_Earnings_c": { - "2014": [300000], - "2015": [500000], - "2016": [700000]} + "SS_Earnings_c": { + "2014": 300000, + "2015": 500000, + "2016": 700000} } } """ diff --git a/taxcalc/tests/test_utils.py b/taxcalc/tests/test_utils.py index a77f3a8df..679d802f2 100644 --- a/taxcalc/tests/test_utils.py +++ b/taxcalc/tests/test_utils.py @@ -74,7 +74,7 @@ def test_create_tables(cps_subsample): calc1 = Calculator(policy=pol, records=rec) calc1.calc_all() # create a policy-reform Policy object and Calculator object calc2 - reform = {2013: {'_II_rt1': [0.15]}} + reform = {'II_rt1': {2013: 0.15}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.calc_all() @@ -592,7 +592,7 @@ def test_diff_table_sum_row(cps_subsample): calc1 = Calculator(policy=pol, records=rec) calc1.calc_all() # create a policy-reform Policy object and Calculator calc2 - reform = {2013: {'_II_rt4': [0.56]}} + reform = {'II_rt4': {2013: 0.56}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.calc_all() @@ -744,7 +744,7 @@ def test_ce_aftertax_income(cps_subsample): calc1.advance_to_year(cyr) calc1.calc_all() # specify calc2 and calc_all() for cyr - reform = {2019: {'_II_em': [1000]}} + reform = {'II_em': {2019: 1000}} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) calc2.advance_to_year(cyr) @@ -816,11 +816,8 @@ def test_dec_graph_plots(cps_subsample): year = 2020 calc1.advance_to_year(year) reform = { - year: { - '_SS_Earnings_c': [9e99], # OASDI FICA tax on all earnings - '_FICA_ss_trt': [0.107484] # lower rate to keep revenue unchanged - - } + 'SS_Earnings_c': {year: 9e99}, # OASDI FICA tax on all earnings + 'FICA_ss_trt': {year: 0.107484} # lower rate to keep revenue unchanged } pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec)