diff --git a/obbba_district_impacts/Congressional-Hackathon-2025 b/obbba_district_impacts/Congressional-Hackathon-2025
new file mode 160000
index 0000000..3f6d05e
--- /dev/null
+++ b/obbba_district_impacts/Congressional-Hackathon-2025
@@ -0,0 +1 @@
+Subproject commit 3f6d05e76400c6e396a3a4eddd34a7b3f6919fc3
diff --git a/us/states/ut/data_exploration.ipynb b/us/states/ut/data_exploration.ipynb
new file mode 100644
index 0000000..add646c
--- /dev/null
+++ b/us/states/ut/data_exploration.ipynb
@@ -0,0 +1,422 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# UT Dataset Exploration\n",
+ "\n",
+ "This notebook explores the Utah (UT) dataset to understand household counts, income distribution, and demographic characteristics."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from policyengine_us import Microsimulation\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "\n",
+ "UT_DATASET = \"hf://policyengine/policyengine-us-data/states/UT.h5\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "348889a2464c4fd8bf369b4288fa9b00",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "UT.h5: 0%| | 0.00/39.1M [00:00, ?B/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Load UT dataset\n",
+ "sim = Microsimulation(dataset=UT_DATASET)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of households in dataset: 17,648\n",
+ "Household count (weighted): 1,015,265\n",
+ "Person count (weighted): 3,467,711\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Check dataset size\n",
+ "household_weight = sim.calculate(\"household_weight\", period=2025)\n",
+ "household_count = sim.calculate(\"household_count\", period=2025, map_to=\"household\")\n",
+ "person_count = sim.calculate(\"person_count\", period=2025, map_to=\"household\")\n",
+ "\n",
+ "print(f\"Number of households in dataset: {len(household_weight):,}\")\n",
+ "print(f\"Household count (weighted): {household_count.sum():,.0f}\")\n",
+ "print(f\"Person count (weighted): {person_count.sum():,.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Income distribution:\n",
+ " Median AGI: $104,469\n",
+ " 75th percentile: $214,444\n",
+ " 90th percentile: $432,171\n",
+ " 95th percentile: $541,148\n",
+ " Max AGI: $3,229,514\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Check household income distribution\n",
+ "agi = sim.calculate(\"adjusted_gross_income\", period=2025, map_to=\"household\")\n",
+ "print(f\"Income distribution:\")\n",
+ "print(f\" Median AGI: ${agi.median():,.0f}\")\n",
+ "print(f\" 75th percentile: ${agi.quantile(0.75):,.0f}\")\n",
+ "print(f\" 90th percentile: ${agi.quantile(0.90):,.0f}\")\n",
+ "print(f\" 95th percentile: ${agi.quantile(0.95):,.0f}\")\n",
+ "print(f\" Max AGI: ${agi.max():,.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Households with children (weighted):\n",
+ " Total households with children: 452,300\n",
+ " Households with 1 child: 167,413\n",
+ " Households with 2 children: 159,249\n",
+ " Households with 3+ children: 125,638\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Check households with children\n",
+ "is_child = sim.calculate(\"is_child\", period=2025, map_to=\"person\")\n",
+ "household_id = sim.calculate(\"household_id\", period=2025, map_to=\"person\")\n",
+ "household_weight = sim.calculate(\"household_weight\", period=2025, map_to=\"person\")\n",
+ "\n",
+ "# Create DataFrame\n",
+ "df_households = pd.DataFrame({\n",
+ " 'household_id': household_id,\n",
+ " 'is_child': is_child,\n",
+ " 'household_weight': household_weight\n",
+ "})\n",
+ "\n",
+ "# Count children per household\n",
+ "children_per_household = df_households.groupby('household_id').agg({\n",
+ " 'is_child': 'sum',\n",
+ " 'household_weight': 'first'\n",
+ "}).reset_index()\n",
+ "\n",
+ "# Calculate weighted household counts\n",
+ "total_households_with_children = children_per_household[children_per_household['is_child'] > 0]['household_weight'].sum()\n",
+ "households_with_1_child = children_per_household[children_per_household['is_child'] == 1]['household_weight'].sum()\n",
+ "households_with_2_children = children_per_household[children_per_household['is_child'] == 2]['household_weight'].sum()\n",
+ "households_with_3plus_children = children_per_household[children_per_household['is_child'] >= 3]['household_weight'].sum()\n",
+ "\n",
+ "print(f\"\\nHouseholds with children (weighted):\")\n",
+ "print(f\" Total households with children: {total_households_with_children:,.0f}\")\n",
+ "print(f\" Households with 1 child: {households_with_1_child:,.0f}\")\n",
+ "print(f\" Households with 2 children: {households_with_2_children:,.0f}\")\n",
+ "print(f\" Households with 3+ children: {households_with_3plus_children:,.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Children by age:\n",
+ " Total children under 18: 931,582\n",
+ " Children under 6: 276,080\n",
+ " Children under 3: 120,763\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Check children by age groups\n",
+ "df = pd.DataFrame({\n",
+ " \"household_id\": sim.calculate(\"household_id\", map_to=\"person\"),\n",
+ " \"tax_unit_id\": sim.calculate(\"tax_unit_id\", map_to=\"person\"),\n",
+ " \"person_id\": sim.calculate(\"person_id\", map_to=\"person\"),\n",
+ " \"age\": sim.calculate(\"age\", map_to=\"person\"),\n",
+ " \"person_weight\": sim.calculate(\"person_weight\", map_to=\"person\")\n",
+ "})\n",
+ "\n",
+ "# Filter for children and apply weights\n",
+ "children_under_18_df = df[df['age'] < 18]\n",
+ "children_under_6_df = df[df['age'] < 6]\n",
+ "children_under_3_df = df[df['age'] < 3]\n",
+ "\n",
+ "# Calculate weighted totals\n",
+ "total_children = children_under_18_df['person_weight'].sum()\n",
+ "children_under_6 = children_under_6_df['person_weight'].sum()\n",
+ "children_under_3 = children_under_3_df['person_weight'].sum()\n",
+ "\n",
+ "print(f\"\\nChildren by age:\")\n",
+ "print(f\" Total children under 18: {total_children:,.0f}\")\n",
+ "print(f\" Children under 6: {children_under_6:,.0f}\")\n",
+ "print(f\" Children under 3: {children_under_3:,.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "============================================================\n",
+ "UT DATASET SUMMARY - WEIGHTED (Population Estimates)\n",
+ "============================================================\n",
+ " Metric Value\n",
+ " Household count (weighted) 1,015,265\n",
+ " Person count (weighted) 3,467,711\n",
+ " Median AGI $104,469\n",
+ " 75th percentile AGI $214,444\n",
+ " 90th percentile AGI $432,171\n",
+ " 95th percentile AGI $541,148\n",
+ " Max AGI $3,229,514\n",
+ "Total households with children 452,300\n",
+ " Households with 1 child 167,413\n",
+ " Households with 2 children 159,249\n",
+ " Households with 3+ children 125,638\n",
+ " Total children under 18 931,582\n",
+ " Children under 6 276,080\n",
+ " Children under 3 120,763\n",
+ "============================================================\n",
+ "\n",
+ "Summary saved to: ut_dataset_summary_weighted.csv\n"
+ ]
+ },
+ {
+ "ename": "",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n",
+ "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n",
+ "\u001b[1;31mClick here for more info. \n",
+ "\u001b[1;31mView Jupyter log for further details."
+ ]
+ }
+ ],
+ "source": [
+ "# Create weighted summary table\n",
+ "weighted_summary_data = {\n",
+ " 'Metric': [\n",
+ " 'Household count (weighted)',\n",
+ " 'Person count (weighted)',\n",
+ " 'Median AGI',\n",
+ " '75th percentile AGI',\n",
+ " '90th percentile AGI',\n",
+ " '95th percentile AGI',\n",
+ " 'Max AGI',\n",
+ " 'Total households with children',\n",
+ " 'Households with 1 child',\n",
+ " 'Households with 2 children',\n",
+ " 'Households with 3+ children',\n",
+ " 'Total children under 18',\n",
+ " 'Children under 6',\n",
+ " 'Children under 3'\n",
+ " ],\n",
+ " 'Value': [\n",
+ " f\"{household_count.sum():,.0f}\",\n",
+ " f\"{person_count.sum():,.0f}\",\n",
+ " f\"${agi.median():,.0f}\",\n",
+ " f\"${agi.quantile(0.75):,.0f}\",\n",
+ " f\"${agi.quantile(0.90):,.0f}\",\n",
+ " f\"${agi.quantile(0.95):,.0f}\",\n",
+ " f\"${agi.max():,.0f}\",\n",
+ " f\"{total_households_with_children:,.0f}\",\n",
+ " f\"{households_with_1_child:,.0f}\",\n",
+ " f\"{households_with_2_children:,.0f}\",\n",
+ " f\"{households_with_3plus_children:,.0f}\",\n",
+ " f\"{total_children:,.0f}\",\n",
+ " f\"{children_under_6:,.0f}\",\n",
+ " f\"{children_under_3:,.0f}\"\n",
+ " ]\n",
+ "}\n",
+ "\n",
+ "weighted_df = pd.DataFrame(weighted_summary_data)\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*60)\n",
+ "print(\"UT DATASET SUMMARY - WEIGHTED (Population Estimates)\")\n",
+ "print(\"=\"*60)\n",
+ "print(weighted_df.to_string(index=False))\n",
+ "print(\"=\"*60)\n",
+ "\n",
+ "# Save table\n",
+ "weighted_df.to_csv('ut_dataset_summary_weighted.csv', index=False)\n",
+ "print(\"\\nSummary saved to: ut_dataset_summary_weighted.csv\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "======================================================================\n",
+ "HOUSEHOLDS WITH $0 INCOME\n",
+ "======================================================================\n",
+ "Household count: 48,395\n",
+ "Percentage of all households: 4.77%\n",
+ "======================================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Households with $0 income\n",
+ "agi_hh = np.array(sim.calculate(\"adjusted_gross_income\", period=2025, map_to=\"household\"))\n",
+ "weights = np.array(sim.calculate(\"household_weight\", period=2025))\n",
+ "\n",
+ "zero_income_mask = agi_hh == 0\n",
+ "zero_income_count = weights[zero_income_mask].sum()\n",
+ "total_households = weights.sum()\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*70)\n",
+ "print(\"HOUSEHOLDS WITH $0 INCOME\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"Household count: {zero_income_count:,.0f}\")\n",
+ "print(f\"Percentage of all households: {zero_income_count / total_households * 100:.2f}%\")\n",
+ "print(\"=\"*70)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "======================================================================\n",
+ "HOUSEHOLD COUNTS BY INCOME BRACKET\n",
+ "======================================================================\n",
+ "Income Bracket Households % of All Households\n",
+ " $0-$10k 126,445 12.45%\n",
+ " $10k-$20k 15,102 1.49%\n",
+ " $20k-$30k 21,610 2.13%\n",
+ " $30k-$40k 71,543 7.05%\n",
+ " $40k-$50k 62,599 6.17%\n",
+ " $50k-$60k 40,115 3.95%\n",
+ "======================================================================\n",
+ "\n",
+ "Total households in $0-$60k range: 337,414\n",
+ "Percentage of all households in $0-$60k range: 33.23%\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Household counts by income brackets\n",
+ "income_brackets = [\n",
+ " (0, 10000, \"$0-$10k\"),\n",
+ " (10000, 20000, \"$10k-$20k\"),\n",
+ " (20000, 30000, \"$20k-$30k\"),\n",
+ " (30000, 40000, \"$30k-$40k\"),\n",
+ " (40000, 50000, \"$40k-$50k\"),\n",
+ " (50000, 60000, \"$50k-$60k\")\n",
+ "]\n",
+ "\n",
+ "bracket_data = []\n",
+ "for lower, upper, label in income_brackets:\n",
+ " mask = (agi_hh >= lower) & (agi_hh < upper)\n",
+ " count = weights[mask].sum()\n",
+ " pct_of_total = (count / total_households) * 100\n",
+ " \n",
+ " bracket_data.append({\n",
+ " \"Income Bracket\": label,\n",
+ " \"Households\": f\"{count:,.0f}\",\n",
+ " \"% of All Households\": f\"{pct_of_total:.2f}%\"\n",
+ " })\n",
+ "\n",
+ "income_df = pd.DataFrame(bracket_data)\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*70)\n",
+ "print(\"HOUSEHOLD COUNTS BY INCOME BRACKET\")\n",
+ "print(\"=\"*70)\n",
+ "print(income_df.to_string(index=False))\n",
+ "print(\"=\"*70)\n",
+ "\n",
+ "# Total in $0-$60k range\n",
+ "total_in_range = sum([weights[(agi_hh >= lower) & (agi_hh < upper)].sum() for lower, upper, _ in income_brackets])\n",
+ "print(f\"\\nTotal households in $0-$60k range: {total_in_range:,.0f}\")\n",
+ "print(f\"Percentage of all households in $0-$60k range: {total_in_range / total_households * 100:.2f}%\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/us/states/ut/ut_ctc_reform_analysis.ipynb b/us/states/ut/ut_ctc_reform_analysis.ipynb
new file mode 100644
index 0000000..6c6e77e
--- /dev/null
+++ b/us/states/ut/ut_ctc_reform_analysis.ipynb
@@ -0,0 +1,518 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Utah CTC Reform Analysis (2025)\n",
+ "\n",
+ "This notebook analyzes the impact of modifying Utah's Child Tax Credit (CTC) reduction start thresholds.\n",
+ "\n",
+ "## Baseline (Current Law)\n",
+ "- Utah CTC phases out at lower income thresholds\n",
+ "\n",
+ "## Reform\n",
+ "- Increase the CTC reduction start thresholds:\n",
+ " - Joint: $59,000\n",
+ " - Single: $48,000\n",
+ " - Separate: $29,500\n",
+ " - Surviving Spouse: $59,000\n",
+ " - Head of Household: $48,000\n",
+ "\n",
+ "## Metrics\n",
+ "We calculate:\n",
+ "- Budgetary impact (net cost)\n",
+ "- Winners (percentage of population affected)\n",
+ "- Overall poverty impact\n",
+ "- Child poverty impact"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from policyengine_us import Microsimulation\n",
+ "from policyengine_core.reforms import Reform\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "\n",
+ "UT_DATASET = \"hf://policyengine/policyengine-us-data/states/UT.h5\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Helper Functions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def calculate_poverty(sim, period=2025, child_only=False):\n",
+ " \"\"\"\n",
+ " Calculate poverty rate and count.\n",
+ " \n",
+ " Args:\n",
+ " sim: Microsimulation object\n",
+ " period: Year to analyze\n",
+ " child_only: If True, only count children under 18\n",
+ " \n",
+ " Returns:\n",
+ " poverty_rate: Weighted poverty rate\n",
+ " people_in_poverty: Weighted count\n",
+ " \"\"\"\n",
+ " age = np.array(sim.calculate(\"age\", period=period))\n",
+ " is_in_poverty = np.array(sim.calculate(\"person_in_poverty\", period=period))\n",
+ " person_weight = np.array(sim.calculate(\"person_weight\", period=period))\n",
+ " \n",
+ " if child_only:\n",
+ " mask = age < 18\n",
+ " else:\n",
+ " mask = np.ones_like(age, dtype=bool)\n",
+ " \n",
+ " # Weighted poverty rate\n",
+ " weighted_in_poverty = (is_in_poverty[mask] * person_weight[mask]).sum()\n",
+ " weighted_total = person_weight[mask].sum()\n",
+ " poverty_rate = weighted_in_poverty / weighted_total if weighted_total > 0 else 0\n",
+ " \n",
+ " # Weighted count of people in poverty\n",
+ " people_in_poverty = weighted_in_poverty\n",
+ " \n",
+ " return {\n",
+ " \"poverty_rate\": poverty_rate,\n",
+ " \"people_in_poverty\": people_in_poverty,\n",
+ " \"total_people\": weighted_total\n",
+ " }\n",
+ "\n",
+ "def calculate_budgetary_impact(baseline_sim, reform_sim, variable, period=2025):\n",
+ " \"\"\"\n",
+ " Calculate the budgetary impact (net cost) of a reform.\n",
+ " \"\"\"\n",
+ " baseline_value = baseline_sim.calculate(variable, period=period, map_to=\"household\").sum()\n",
+ " reform_value = reform_sim.calculate(variable, period=period, map_to=\"household\").sum()\n",
+ " \n",
+ " return reform_value - baseline_value\n",
+ "\n",
+ "def calculate_winners(baseline_sim, reform_sim, period=2025):\n",
+ " \"\"\"\n",
+ " Calculate winners from a reform at the person level (weighted).\n",
+ " Winners: People in households with higher net income under reform.\n",
+ " Returns weighted count and percentage of total population.\n",
+ " \"\"\"\n",
+ " # Get household-level income change\n",
+ " baseline_income = np.array(baseline_sim.calculate(\"household_net_income\", period=period, map_to=\"household\"))\n",
+ " reform_income = np.array(reform_sim.calculate(\"household_net_income\", period=period, map_to=\"household\"))\n",
+ " household_weight = np.array(baseline_sim.calculate(\"household_weight\", period=period))\n",
+ " income_change = reform_income - baseline_income\n",
+ " \n",
+ " # Get person-level data\n",
+ " household_id_person = np.array(baseline_sim.calculate(\"household_id\", period=period, map_to=\"person\"))\n",
+ " household_id_household = np.array(baseline_sim.calculate(\"household_id\", period=period, map_to=\"household\"))\n",
+ " person_weight = np.array(baseline_sim.calculate(\"person_weight\", period=period))\n",
+ " \n",
+ " # Create mapping of household_id to income_change\n",
+ " income_change_dict = dict(zip(household_id_household, income_change))\n",
+ " \n",
+ " # Map income change to each person\n",
+ " person_income_change = np.array([income_change_dict.get(hh_id, 0) for hh_id in household_id_person])\n",
+ " \n",
+ " # Weighted count of people who are winners (gained more than $1)\n",
+ " winners_mask = person_income_change > 1\n",
+ " people_winning = person_weight[winners_mask].sum()\n",
+ " total_people = person_weight.sum()\n",
+ " \n",
+ " # Calculate percentage\n",
+ " pct_winners = (people_winning / total_people * 100) if total_people > 0 else 0\n",
+ " \n",
+ " # Average gain for winning households (weighted)\n",
+ " winning_hh_mask = income_change > 1\n",
+ " if winning_hh_mask.sum() > 0:\n",
+ " avg_gain = np.average(income_change[winning_hh_mask], weights=household_weight[winning_hh_mask])\n",
+ " else:\n",
+ " avg_gain = 0\n",
+ " \n",
+ " return {\n",
+ " \"people_winning\": people_winning,\n",
+ " \"total_people\": total_people,\n",
+ " \"pct_winners\": pct_winners,\n",
+ " \"avg_gain\": avg_gain\n",
+ " }\n",
+ "\n",
+ "def format_currency(value):\n",
+ " \"\"\"Format value as currency in millions.\"\"\"\n",
+ " return f\"${value/1e6:.2f}M\"\n",
+ "\n",
+ "def format_percent(value):\n",
+ " \"\"\"Format value as percentage.\"\"\"\n",
+ " return f\"{value*100:.2f}%\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Define Baseline and Reform"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Reform function defined!\n"
+ ]
+ }
+ ],
+ "source": [
+ "def create_ctc_reform():\n",
+ " \"\"\"Reform: Modify Utah CTC reduction start thresholds\"\"\"\n",
+ " reform = Reform.from_dict(\n",
+ " {\n",
+ " \"gov.states.ut.tax.income.credits.ctc.reduction.start.JOINT\": {\n",
+ " \"2025-01-01.2100-12-31\": 59000\n",
+ " },\n",
+ " \"gov.states.ut.tax.income.credits.ctc.reduction.start.SINGLE\": {\n",
+ " \"2025-01-01.2100-12-31\": 48000\n",
+ " },\n",
+ " \"gov.states.ut.tax.income.credits.ctc.reduction.start.SEPARATE\": {\n",
+ " \"2025-01-01.2100-12-31\": 29500\n",
+ " },\n",
+ " \"gov.states.ut.tax.income.credits.ctc.reduction.start.SURVIVING_SPOUSE\": {\n",
+ " \"2025-01-01.2100-12-31\": 59000\n",
+ " },\n",
+ " \"gov.states.ut.tax.income.credits.ctc.reduction.start.HEAD_OF_HOUSEHOLD\": {\n",
+ " \"2025-01-01.2100-12-31\": 48000\n",
+ " }\n",
+ " },\n",
+ " country_id=\"us\",\n",
+ " )\n",
+ " return reform\n",
+ "\n",
+ "print(\"Reform function defined!\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Load Simulations"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Loading baseline (current law - existing UT CTC thresholds)...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "4800beb926e6478dba5cabaf93483ef4",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "UT.h5: 0%| | 0.00/39.1M [00:00, ?B/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Baseline loaded\n",
+ "\n",
+ "Loading reform (modified CTC reduction start thresholds)...\n",
+ "Reform loaded\n",
+ "\n",
+ "============================================================\n",
+ "All simulations ready!\n",
+ "============================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"Loading baseline (current law - existing UT CTC thresholds)...\")\n",
+ "baseline = Microsimulation(dataset=UT_DATASET)\n",
+ "print(\"Baseline loaded\")\n",
+ "\n",
+ "print(\"\\nLoading reform (modified CTC reduction start thresholds)...\")\n",
+ "reform = create_ctc_reform()\n",
+ "reform_sim = Microsimulation(dataset=UT_DATASET, reform=reform)\n",
+ "print(\"Reform loaded\")\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*60)\n",
+ "print(\"All simulations ready!\")\n",
+ "print(\"=\"*60)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Calculate Impacts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "All impacts calculated\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Baseline metrics\n",
+ "baseline_overall_pov = calculate_poverty(baseline, child_only=False)\n",
+ "baseline_child_pov = calculate_poverty(baseline, child_only=True)\n",
+ "\n",
+ "# Reform metrics\n",
+ "reform_overall_pov = calculate_poverty(reform_sim, child_only=False)\n",
+ "reform_child_pov = calculate_poverty(reform_sim, child_only=True)\n",
+ "\n",
+ "# Budgetary impact - calculated as increase in household net income (cost to state)\n",
+ "baseline_hh_income = baseline.calculate(\"household_net_income\", period=2025, map_to=\"household\").sum()\n",
+ "reform_hh_income = reform_sim.calculate(\"household_net_income\", period=2025, map_to=\"household\").sum()\n",
+ "ctc_cost = reform_hh_income - baseline_hh_income\n",
+ "\n",
+ "# Winners (at person level)\n",
+ "winners = calculate_winners(baseline, reform_sim)\n",
+ "\n",
+ "print(\"All impacts calculated\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Results Summary"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "================================================================================\n",
+ "UTAH CTC REFORM IMPACTS (2025)\n",
+ "Baseline: Current CTC thresholds | Reform: Increased reduction start thresholds\n",
+ "================================================================================\n",
+ "\n",
+ "================================BUDGETARY IMPACT================================\n",
+ "UT CTC Reform net cost: $10.08M\n",
+ "\n",
+ "==============================WINNERS (POPULATION)==============================\n",
+ "People gaining income: 136,260 (3.93% of population)\n",
+ "Average gain per household: $399.43\n",
+ "\n",
+ "============================POVERTY IMPACT - OVERALL============================\n",
+ "Baseline poverty rate: 8.29%\n",
+ "Reform poverty rate: 8.29%\n",
+ "Absolute reduction: 0.00%\n",
+ "Relative reduction: 0.00%\n",
+ "People lifted from poverty: 0\n",
+ "\n",
+ "===========================POVERTY IMPACT - CHILDREN============================\n",
+ "Baseline child poverty rate: 6.37%\n",
+ "Reform child poverty rate: 6.37%\n",
+ "Absolute reduction: 0.00%\n",
+ "Relative reduction: 0.00%\n",
+ "Children lifted from poverty: 0\n",
+ "================================================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"\\n\" + \"=\"*80)\n",
+ "print(\"UTAH CTC REFORM IMPACTS (2025)\")\n",
+ "print(\"Baseline: Current CTC thresholds | Reform: Increased reduction start thresholds\")\n",
+ "print(\"=\"*80)\n",
+ "\n",
+ "print(f\"\\n{'BUDGETARY IMPACT':=^80}\")\n",
+ "print(f\"UT CTC Reform net cost: {format_currency(ctc_cost)}\")\n",
+ "\n",
+ "print(f\"\\n{'WINNERS (POPULATION)':=^80}\")\n",
+ "print(f\"People gaining income: {winners['people_winning']:,.0f} ({winners['pct_winners']:.2f}% of population)\")\n",
+ "print(f\"Average gain per household: ${winners['avg_gain']:,.2f}\")\n",
+ "\n",
+ "print(f\"\\n{'POVERTY IMPACT - OVERALL':=^80}\")\n",
+ "print(f\"Baseline poverty rate: {format_percent(baseline_overall_pov['poverty_rate'])}\")\n",
+ "print(f\"Reform poverty rate: {format_percent(reform_overall_pov['poverty_rate'])}\")\n",
+ "overall_pov_reduction = baseline_overall_pov['poverty_rate'] - reform_overall_pov['poverty_rate']\n",
+ "overall_pov_pct_reduction = (overall_pov_reduction / baseline_overall_pov['poverty_rate'] * 100) if baseline_overall_pov['poverty_rate'] > 0 else 0\n",
+ "print(f\"Absolute reduction: {format_percent(overall_pov_reduction)}\")\n",
+ "print(f\"Relative reduction: {overall_pov_pct_reduction:.2f}%\")\n",
+ "people_lifted = baseline_overall_pov['people_in_poverty'] - reform_overall_pov['people_in_poverty']\n",
+ "print(f\"People lifted from poverty: {people_lifted:,.0f}\")\n",
+ "\n",
+ "print(f\"\\n{'POVERTY IMPACT - CHILDREN':=^80}\")\n",
+ "print(f\"Baseline child poverty rate: {format_percent(baseline_child_pov['poverty_rate'])}\")\n",
+ "print(f\"Reform child poverty rate: {format_percent(reform_child_pov['poverty_rate'])}\")\n",
+ "child_pov_reduction = baseline_child_pov['poverty_rate'] - reform_child_pov['poverty_rate']\n",
+ "child_pov_pct_reduction = (child_pov_reduction / baseline_child_pov['poverty_rate'] * 100) if baseline_child_pov['poverty_rate'] > 0 else 0\n",
+ "print(f\"Absolute reduction: {format_percent(child_pov_reduction)}\")\n",
+ "print(f\"Relative reduction: {child_pov_pct_reduction:.2f}%\")\n",
+ "children_lifted = baseline_child_pov['people_in_poverty'] - reform_child_pov['people_in_poverty']\n",
+ "print(f\"Children lifted from poverty: {children_lifted:,.0f}\")\n",
+ "print(\"=\"*80)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "HOUSEHOLDS BENEFITTING FROM UT CTC REFORM\n",
+ "======================================================================\n",
+ "Households benefitting: 25,237\n",
+ "Total households: 1,015,265\n",
+ "Percentage of households: 2.49%\n",
+ "======================================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Calculate households benefitting (weighted)\n",
+ "baseline_hh_income = np.array(baseline.calculate(\"household_net_income\", period=2025, map_to=\"household\"))\n",
+ "reform_hh_income = np.array(reform_sim.calculate(\"household_net_income\", period=2025, map_to=\"household\"))\n",
+ "household_weight = np.array(baseline.calculate(\"household_weight\", period=2025))\n",
+ "\n",
+ "hh_income_change = reform_hh_income - baseline_hh_income\n",
+ "hh_benefitting_mask = hh_income_change > 1 # Gained more than $1\n",
+ "\n",
+ "households_benefitting = household_weight[hh_benefitting_mask].sum()\n",
+ "total_households = household_weight.sum()\n",
+ "pct_households_benefitting = (households_benefitting / total_households) * 100\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"HOUSEHOLDS BENEFITTING FROM UT CTC REFORM\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"Households benefitting: {households_benefitting:,.0f}\")\n",
+ "print(f\"Total households: {total_households:,.0f}\")\n",
+ "print(f\"Percentage of households: {pct_households_benefitting:.2f}%\")\n",
+ "print(\"=\"*70)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Export Results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "==============================================================================================================\n",
+ "UT CTC REFORM SUMMARY\n",
+ "==============================================================================================================\n",
+ " Scenario Description Net Cost Overall Poverty Change (%) Child Poverty Change (%) % Population Winning\n",
+ "CTC Reform Increased CTC reduction start thresholds $10.08M 0.00% 0.00% 3.93%\n",
+ "==============================================================================================================\n",
+ "\n",
+ "Exported to: ut_ctc_reform_results.csv\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Calculate poverty changes\n",
+ "overall_pov_reduction = baseline_overall_pov['poverty_rate'] - reform_overall_pov['poverty_rate']\n",
+ "overall_pov_pct_reduction = (overall_pov_reduction / baseline_overall_pov['poverty_rate'] * 100) if baseline_overall_pov['poverty_rate'] > 0 else 0\n",
+ "child_pov_reduction = baseline_child_pov['poverty_rate'] - reform_child_pov['poverty_rate']\n",
+ "child_pov_pct_reduction = (child_pov_reduction / baseline_child_pov['poverty_rate'] * 100) if baseline_child_pov['poverty_rate'] > 0 else 0\n",
+ "\n",
+ "# Create results DataFrame (reform only)\n",
+ "results = [\n",
+ " {\n",
+ " \"Scenario\": \"CTC Reform\",\n",
+ " \"Description\": \"Increased CTC reduction start thresholds\",\n",
+ " \"Net Cost\": format_currency(ctc_cost),\n",
+ " \"Overall Poverty Change (%)\": f\"{overall_pov_pct_reduction:.2f}%\",\n",
+ " \"Child Poverty Change (%)\": f\"{child_pov_pct_reduction:.2f}%\",\n",
+ " \"% Population Winning\": f\"{winners['pct_winners']:.2f}%\"\n",
+ " }\n",
+ "]\n",
+ "\n",
+ "df_results = pd.DataFrame(results)\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*110)\n",
+ "print(\"UT CTC REFORM SUMMARY\")\n",
+ "print(\"=\"*110)\n",
+ "print(df_results.to_string(index=False))\n",
+ "print(\"=\"*110)\n",
+ "\n",
+ "# Export to CSV\n",
+ "df_results.to_csv(\"ut_ctc_reform_results.csv\", index=False)\n",
+ "print(\"\\nExported to: ut_ctc_reform_results.csv\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/us/states/ut/ut_ctc_reform_results.csv b/us/states/ut/ut_ctc_reform_results.csv
new file mode 100644
index 0000000..cd793ce
--- /dev/null
+++ b/us/states/ut/ut_ctc_reform_results.csv
@@ -0,0 +1,2 @@
+Scenario,Description,Net Cost,Overall Poverty Change (%),Child Poverty Change (%),% Population Winning
+CTC Reform,Increased CTC reduction start thresholds,$10.08M,0.00%,0.00%,3.93%
diff --git a/us/states/ut/ut_dataset_summary_weighted.csv b/us/states/ut/ut_dataset_summary_weighted.csv
new file mode 100644
index 0000000..71d2eac
--- /dev/null
+++ b/us/states/ut/ut_dataset_summary_weighted.csv
@@ -0,0 +1,15 @@
+Metric,Value
+Household count (weighted),"1,015,265"
+Person count (weighted),"3,467,711"
+Median AGI,"$104,469"
+75th percentile AGI,"$214,444"
+90th percentile AGI,"$432,171"
+95th percentile AGI,"$541,148"
+Max AGI,"$3,229,514"
+Total households with children,"452,300"
+Households with 1 child,"167,413"
+Households with 2 children,"159,249"
+Households with 3+ children,"125,638"
+Total children under 18,"931,582"
+Children under 6,"276,080"
+Children under 3,"120,763"
diff --git a/us/states/ut/ut_eitc_reform_analysis.ipynb b/us/states/ut/ut_eitc_reform_analysis.ipynb
new file mode 100644
index 0000000..953cd25
--- /dev/null
+++ b/us/states/ut/ut_eitc_reform_analysis.ipynb
@@ -0,0 +1,489 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Utah EITC Reform Analysis (2025)\n",
+ "\n",
+ "This notebook analyzes the impact of making Utah's Earned Income Tax Credit (EITC) refundable for families with young children.\n",
+ "\n",
+ "## Baseline (Current Law)\n",
+ "- Utah EITC matches 20% of the federal EITC\n",
+ "- The credit is non-refundable\n",
+ "\n",
+ "## Reform\n",
+ "- Make the Utah EITC fully refundable for households with children age 2 or younger\n",
+ "\n",
+ "## Metrics\n",
+ "We calculate:\n",
+ "- Budgetary impact (net cost)\n",
+ "- Winners (percentage of population affected)\n",
+ "- Overall poverty impact\n",
+ "- Child poverty impact"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from policyengine_us import Microsimulation\n",
+ "from policyengine_core.reforms import Reform\n",
+ "from policyengine_us.reforms.states.ut.ut_refundable_eitc import ut_refundable_eitc\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "\n",
+ "UT_DATASET = \"hf://policyengine/policyengine-us-data/states/UT.h5\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Helper Functions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def calculate_poverty(sim, period=2025, child_only=False):\n",
+ " \"\"\"\n",
+ " Calculate poverty rate and count.\n",
+ " \n",
+ " Args:\n",
+ " sim: Microsimulation object\n",
+ " period: Year to analyze\n",
+ " child_only: If True, only count children under 18\n",
+ " \n",
+ " Returns:\n",
+ " poverty_rate: Weighted poverty rate\n",
+ " people_in_poverty: Weighted count\n",
+ " \"\"\"\n",
+ " age = np.array(sim.calculate(\"age\", period=period))\n",
+ " is_in_poverty = np.array(sim.calculate(\"person_in_poverty\", period=period))\n",
+ " person_weight = np.array(sim.calculate(\"person_weight\", period=period))\n",
+ " \n",
+ " if child_only:\n",
+ " mask = age < 18\n",
+ " else:\n",
+ " mask = np.ones_like(age, dtype=bool)\n",
+ " \n",
+ " # Weighted poverty rate\n",
+ " weighted_in_poverty = (is_in_poverty[mask] * person_weight[mask]).sum()\n",
+ " weighted_total = person_weight[mask].sum()\n",
+ " poverty_rate = weighted_in_poverty / weighted_total if weighted_total > 0 else 0\n",
+ " \n",
+ " # Weighted count of people in poverty\n",
+ " people_in_poverty = weighted_in_poverty\n",
+ " \n",
+ " return {\n",
+ " \"poverty_rate\": poverty_rate,\n",
+ " \"people_in_poverty\": people_in_poverty,\n",
+ " \"total_people\": weighted_total\n",
+ " }\n",
+ "\n",
+ "def calculate_budgetary_impact(baseline_sim, reform_sim, variable, period=2025):\n",
+ " \"\"\"\n",
+ " Calculate the budgetary impact (net cost) of a reform.\n",
+ " \"\"\"\n",
+ " baseline_value = baseline_sim.calculate(variable, period=period, map_to=\"household\").sum()\n",
+ " reform_value = reform_sim.calculate(variable, period=period, map_to=\"household\").sum()\n",
+ " \n",
+ " return reform_value - baseline_value\n",
+ "\n",
+ "def calculate_winners(baseline_sim, reform_sim, period=2025):\n",
+ " \"\"\"\n",
+ " Calculate winners from a reform at the person level (weighted).\n",
+ " Winners: People in households with higher net income under reform.\n",
+ " Returns weighted count and percentage of total population.\n",
+ " \"\"\"\n",
+ " # Get household-level income change\n",
+ " baseline_income = np.array(baseline_sim.calculate(\"household_net_income\", period=period, map_to=\"household\"))\n",
+ " reform_income = np.array(reform_sim.calculate(\"household_net_income\", period=period, map_to=\"household\"))\n",
+ " household_weight = np.array(baseline_sim.calculate(\"household_weight\", period=period))\n",
+ " income_change = reform_income - baseline_income\n",
+ " \n",
+ " # Get person-level data\n",
+ " household_id_person = np.array(baseline_sim.calculate(\"household_id\", period=period, map_to=\"person\"))\n",
+ " household_id_household = np.array(baseline_sim.calculate(\"household_id\", period=period, map_to=\"household\"))\n",
+ " person_weight = np.array(baseline_sim.calculate(\"person_weight\", period=period))\n",
+ " \n",
+ " # Create mapping of household_id to income_change\n",
+ " income_change_dict = dict(zip(household_id_household, income_change))\n",
+ " \n",
+ " # Map income change to each person\n",
+ " person_income_change = np.array([income_change_dict.get(hh_id, 0) for hh_id in household_id_person])\n",
+ " \n",
+ " # Weighted count of people who are winners (gained more than $1)\n",
+ " winners_mask = person_income_change > 1\n",
+ " people_winning = person_weight[winners_mask].sum()\n",
+ " total_people = person_weight.sum()\n",
+ " \n",
+ " # Calculate percentage\n",
+ " pct_winners = (people_winning / total_people * 100) if total_people > 0 else 0\n",
+ " \n",
+ " # Average gain for winning households (weighted)\n",
+ " winning_hh_mask = income_change > 1\n",
+ " if winning_hh_mask.sum() > 0:\n",
+ " avg_gain = np.average(income_change[winning_hh_mask], weights=household_weight[winning_hh_mask])\n",
+ " else:\n",
+ " avg_gain = 0\n",
+ " \n",
+ " return {\n",
+ " \"people_winning\": people_winning,\n",
+ " \"total_people\": total_people,\n",
+ " \"pct_winners\": pct_winners,\n",
+ " \"avg_gain\": avg_gain\n",
+ " }\n",
+ "\n",
+ "def format_currency(value):\n",
+ " \"\"\"Format value as currency in millions.\"\"\"\n",
+ " return f\"${value/1e6:.2f}M\"\n",
+ "\n",
+ "def format_percent(value):\n",
+ " \"\"\"Format value as percentage.\"\"\"\n",
+ " return f\"{value*100:.2f}%\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Define Baseline and Reform"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Reform functions defined!\n"
+ ]
+ }
+ ],
+ "source": [
+ "def create_reform():\n",
+ " \"\"\"Reform: Make UT EITC refundable for households with children age 2 or younger\"\"\"\n",
+ " param_reform = Reform.from_dict(\n",
+ " {\n",
+ " \"gov.contrib.states.ut.eitc.in_effect\": {\n",
+ " \"2025-01-01.2100-12-31\": True\n",
+ " }\n",
+ " },\n",
+ " country_id=\"us\",\n",
+ " )\n",
+ " # Combine the parameter reform with the structural reform\n",
+ " return (param_reform, ut_refundable_eitc)\n",
+ "\n",
+ "print(\"Reform functions defined!\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Load Simulations"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Loading baseline (current law - non-refundable UT EITC at 20%)...\n",
+ "Baseline loaded\n",
+ "\n",
+ "Loading reform (refundable UT EITC for families with young children)...\n",
+ "Reform loaded\n",
+ "\n",
+ "============================================================\n",
+ "All simulations ready!\n",
+ "============================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"Loading baseline (current law - non-refundable UT EITC at 20%)...\")\n",
+ "baseline = Microsimulation(dataset=UT_DATASET)\n",
+ "print(\"Baseline loaded\")\n",
+ "\n",
+ "print(\"\\nLoading reform (refundable UT EITC for families with young children)...\")\n",
+ "reform = create_reform()\n",
+ "reform_sim = Microsimulation(dataset=UT_DATASET, reform=reform)\n",
+ "print(\"Reform loaded\")\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*60)\n",
+ "print(\"All simulations ready!\")\n",
+ "print(\"=\"*60)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Calculate Impacts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "All impacts calculated\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Baseline metrics\n",
+ "baseline_overall_pov = calculate_poverty(baseline, child_only=False)\n",
+ "baseline_child_pov = calculate_poverty(baseline, child_only=True)\n",
+ "\n",
+ "# Reform metrics\n",
+ "reform_overall_pov = calculate_poverty(reform_sim, child_only=False)\n",
+ "reform_child_pov = calculate_poverty(reform_sim, child_only=True)\n",
+ "\n",
+ "# Budgetary impact - calculated as increase in household net income (cost to state)\n",
+ "# The refundable EITC variable only exists in reform, so we use net income change\n",
+ "baseline_hh_income = baseline.calculate(\"household_net_income\", period=2025, map_to=\"household\").sum()\n",
+ "reform_hh_income = reform_sim.calculate(\"household_net_income\", period=2025, map_to=\"household\").sum()\n",
+ "eitc_cost = reform_hh_income - baseline_hh_income\n",
+ "\n",
+ "# Winners (at person level)\n",
+ "winners = calculate_winners(baseline, reform_sim)\n",
+ "\n",
+ "print(\"All impacts calculated\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Results Summary"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "================================================================================\n",
+ "UTAH EITC REFORM IMPACTS (2025)\n",
+ "Baseline: Non-refundable UT EITC at 20% | Reform: Refundable for families with children age 0-2\n",
+ "================================================================================\n",
+ "\n",
+ "================================BUDGETARY IMPACT================================\n",
+ "UT Refundable EITC net cost: $14.22M\n",
+ "\n",
+ "==============================WINNERS (POPULATION)==============================\n",
+ "People gaining income: 98,777 (2.85% of population)\n",
+ "Average gain per household: $668.61\n",
+ "\n",
+ "============================POVERTY IMPACT - OVERALL============================\n",
+ "Baseline poverty rate: 8.32%\n",
+ "Reform poverty rate: 8.04%\n",
+ "Absolute reduction: 0.27%\n",
+ "Relative reduction: 3.29%\n",
+ "People lifted from poverty: 9,497\n",
+ "\n",
+ "===========================POVERTY IMPACT - CHILDREN============================\n",
+ "Baseline child poverty rate: 6.37%\n",
+ "Reform child poverty rate: 5.87%\n",
+ "Absolute reduction: 0.50%\n",
+ "Relative reduction: 7.84%\n",
+ "Children lifted from poverty: 4,749\n",
+ "================================================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"\\n\" + \"=\"*80)\n",
+ "print(\"UTAH EITC REFORM IMPACTS (2025)\")\n",
+ "print(\"Baseline: Non-refundable UT EITC at 20% | Reform: Refundable for families with children age 0-2\")\n",
+ "print(\"=\"*80)\n",
+ "\n",
+ "print(f\"\\n{'BUDGETARY IMPACT':=^80}\")\n",
+ "print(f\"UT Refundable EITC net cost: {format_currency(eitc_cost)}\")\n",
+ "\n",
+ "print(f\"\\n{'WINNERS (POPULATION)':=^80}\")\n",
+ "print(f\"People gaining income: {winners['people_winning']:,.0f} ({winners['pct_winners']:.2f}% of population)\")\n",
+ "print(f\"Average gain per household: ${winners['avg_gain']:,.2f}\")\n",
+ "\n",
+ "print(f\"\\n{'POVERTY IMPACT - OVERALL':=^80}\")\n",
+ "print(f\"Baseline poverty rate: {format_percent(baseline_overall_pov['poverty_rate'])}\")\n",
+ "print(f\"Reform poverty rate: {format_percent(reform_overall_pov['poverty_rate'])}\")\n",
+ "overall_pov_reduction = baseline_overall_pov['poverty_rate'] - reform_overall_pov['poverty_rate']\n",
+ "overall_pov_pct_reduction = (overall_pov_reduction / baseline_overall_pov['poverty_rate'] * 100) if baseline_overall_pov['poverty_rate'] > 0 else 0\n",
+ "print(f\"Absolute reduction: {format_percent(overall_pov_reduction)}\")\n",
+ "print(f\"Relative reduction: {overall_pov_pct_reduction:.2f}%\")\n",
+ "people_lifted = baseline_overall_pov['people_in_poverty'] - reform_overall_pov['people_in_poverty']\n",
+ "print(f\"People lifted from poverty: {people_lifted:,.0f}\")\n",
+ "\n",
+ "print(f\"\\n{'POVERTY IMPACT - CHILDREN':=^80}\")\n",
+ "print(f\"Baseline child poverty rate: {format_percent(baseline_child_pov['poverty_rate'])}\")\n",
+ "print(f\"Reform child poverty rate: {format_percent(reform_child_pov['poverty_rate'])}\")\n",
+ "child_pov_reduction = baseline_child_pov['poverty_rate'] - reform_child_pov['poverty_rate']\n",
+ "child_pov_pct_reduction = (child_pov_reduction / baseline_child_pov['poverty_rate'] * 100) if baseline_child_pov['poverty_rate'] > 0 else 0\n",
+ "print(f\"Absolute reduction: {format_percent(child_pov_reduction)}\")\n",
+ "print(f\"Relative reduction: {child_pov_pct_reduction:.2f}%\")\n",
+ "children_lifted = baseline_child_pov['people_in_poverty'] - reform_child_pov['people_in_poverty']\n",
+ "print(f\"Children lifted from poverty: {children_lifted:,.0f}\")\n",
+ "print(\"=\"*80)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "HOUSEHOLDS BENEFITTING FROM UT REFUNDABLE EITC\n",
+ "======================================================================\n",
+ "Households benefitting: 21,262\n",
+ "Total households: 1,015,265\n",
+ "Percentage of households: 2.09%\n",
+ "======================================================================\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Calculate households benefitting (weighted)\n",
+ "baseline_hh_income = np.array(baseline.calculate(\"household_net_income\", period=2025, map_to=\"household\"))\n",
+ "reform_hh_income = np.array(reform_sim.calculate(\"household_net_income\", period=2025, map_to=\"household\"))\n",
+ "household_weight = np.array(baseline.calculate(\"household_weight\", period=2025))\n",
+ "\n",
+ "hh_income_change = reform_hh_income - baseline_hh_income\n",
+ "hh_benefitting_mask = hh_income_change > 1 # Gained more than $1\n",
+ "\n",
+ "households_benefitting = household_weight[hh_benefitting_mask].sum()\n",
+ "total_households = household_weight.sum()\n",
+ "pct_households_benefitting = (households_benefitting / total_households) * 100\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"HOUSEHOLDS BENEFITTING FROM UT REFUNDABLE EITC\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"Households benefitting: {households_benefitting:,.0f}\")\n",
+ "print(f\"Total households: {total_households:,.0f}\")\n",
+ "print(f\"Percentage of households: {pct_households_benefitting:.2f}%\")\n",
+ "print(\"=\"*70)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Export Results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "==============================================================================================================\n",
+ "UT EITC REFORM SUMMARY\n",
+ "==============================================================================================================\n",
+ "Scenario Description Net Cost Overall Poverty Change (%) Child Poverty Change (%) % Population Winning\n",
+ " Reform Refundable EITC for children age 0-2 $14.22M 3.29% 7.84% 2.85%\n",
+ "==============================================================================================================\n",
+ "\n",
+ "Exported to: ut_eitc_reform_results.csv\n"
+ ]
+ },
+ {
+ "ename": "",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n",
+ "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n",
+ "\u001b[1;31mClick here for more info. \n",
+ "\u001b[1;31mView Jupyter log for further details."
+ ]
+ }
+ ],
+ "source": [
+ "# Calculate poverty changes\n",
+ "overall_pov_reduction = baseline_overall_pov['poverty_rate'] - reform_overall_pov['poverty_rate']\n",
+ "overall_pov_pct_reduction = (overall_pov_reduction / baseline_overall_pov['poverty_rate'] * 100) if baseline_overall_pov['poverty_rate'] > 0 else 0\n",
+ "child_pov_reduction = baseline_child_pov['poverty_rate'] - reform_child_pov['poverty_rate']\n",
+ "child_pov_pct_reduction = (child_pov_reduction / baseline_child_pov['poverty_rate'] * 100) if baseline_child_pov['poverty_rate'] > 0 else 0\n",
+ "\n",
+ "# Create results DataFrame (reform only)\n",
+ "results = [\n",
+ " {\n",
+ " \"Scenario\": \"Reform\",\n",
+ " \"Description\": \"Refundable EITC for children age 0-2\",\n",
+ " \"Net Cost\": format_currency(eitc_cost),\n",
+ " \"Overall Poverty Change (%)\": f\"{overall_pov_pct_reduction:.2f}%\",\n",
+ " \"Child Poverty Change (%)\": f\"{child_pov_pct_reduction:.2f}%\",\n",
+ " \"% Population Winning\": f\"{winners['pct_winners']:.2f}%\"\n",
+ " }\n",
+ "]\n",
+ "\n",
+ "df_results = pd.DataFrame(results)\n",
+ "\n",
+ "print(\"\\n\" + \"=\"*110)\n",
+ "print(\"UT EITC REFORM SUMMARY\")\n",
+ "print(\"=\"*110)\n",
+ "print(df_results.to_string(index=False))\n",
+ "print(\"=\"*110)\n",
+ "\n",
+ "# Export to CSV\n",
+ "df_results.to_csv(\"ut_eitc_reform_results.csv\", index=False)\n",
+ "print(\"\\nExported to: ut_eitc_reform_results.csv\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/us/states/ut/ut_eitc_reform_results.csv b/us/states/ut/ut_eitc_reform_results.csv
new file mode 100644
index 0000000..3671953
--- /dev/null
+++ b/us/states/ut/ut_eitc_reform_results.csv
@@ -0,0 +1,2 @@
+Scenario,Description,Net Cost,Overall Poverty Change (%),Child Poverty Change (%),% Population Winning
+Reform,Refundable EITC for children age 0-2,$14.22M,3.29%,7.84%,2.85%
diff --git a/us/states/ut/ut_refundable_eitc_household_examples_v2.ipynb b/us/states/ut/ut_refundable_eitc_household_examples_v2.ipynb
new file mode 100644
index 0000000..290598d
--- /dev/null
+++ b/us/states/ut/ut_refundable_eitc_household_examples_v2.ipynb
@@ -0,0 +1,1140 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# UT Refundable EITC - Household Example Calculations\n",
+ "\n",
+ "This notebook verifies the UT refundable EITC reform is working correctly by examining individual household examples.\n",
+ "\n",
+ "## Reform Summary\n",
+ "- **Baseline**: Utah EITC = 20% of federal EITC (non-refundable, limited by tax liability)\n",
+ "- **Reform**: Makes the UT EITC fully refundable for households with a qualifying child age 2 or younger\n",
+ "\n",
+ "## Expected Behavior\n",
+ "1. Households with child age <= 2: Full UT EITC becomes refundable\n",
+ "2. Households with children only age 3+: UT EITC remains non-refundable\n",
+ "3. Childless households: UT EITC remains non-refundable"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from policyengine_us import Microsimulation, Simulation\n",
+ "from policyengine_core.reforms import Reform\n",
+ "from policyengine_us.reforms.states.ut.ut_refundable_eitc import ut_refundable_eitc\n",
+ "import pandas as pd\n",
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def create_reform():\n",
+ " \"\"\"Reform: Make UT EITC refundable for households with children age 2 or younger\"\"\"\n",
+ " param_reform = Reform.from_dict(\n",
+ " {\n",
+ " \"gov.contrib.states.ut.eitc.in_effect\": {\n",
+ " \"2025-01-01.2100-12-31\": True\n",
+ " }\n",
+ " },\n",
+ " country_id=\"us\",\n",
+ " )\n",
+ " return (param_reform, ut_refundable_eitc)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 1: Single Parent with 1-year-old (Should Benefit)\n",
+ "\n",
+ "Low-income single parent with an infant - should get full refundable EITC"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 1: Single Parent with 1-year-old, $20k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $4,328.00\n",
+ "UT EITC (20% of federal): $865.60\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $900.00\n",
+ " UT non-refundable credits: $1,865.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $48,480.62\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: True\n",
+ " UT refundable EITC: $865.60\n",
+ " UT non-refundable EITC: $0.00\n",
+ " UT non-refundable credits: $1,000.00\n",
+ " UT refundable credits: $865.60\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $-865.60\n",
+ " Household net income: $49,346.22\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $865.60\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_1 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 28}, \"employment_income\": {2025: 20_000}},\n",
+ " \"child\": {\"age\": {2025: 1}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_1 = Simulation(situation=situation_1)\n",
+ "reform_1 = Simulation(situation=situation_1, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 1: Single Parent with 1-year-old, $20k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_1.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_1.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_1.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_1.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_1.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_1.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_1.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_1.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_1.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_1.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_1.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_1.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_1.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_1.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_1.calculate('household_net_income', 2025)[0] - baseline_1.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 2: Single Parent with 5-year-old (Should NOT Benefit)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 2: Single Parent with 5-year-old, $20k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $4,328.00\n",
+ "UT EITC (20% of federal): $865.60\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $900.00\n",
+ " UT non-refundable credits: $1,865.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $28,016.10\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: False\n",
+ " UT refundable EITC: $0.00\n",
+ " UT non-refundable EITC: $865.60\n",
+ " UT non-refundable credits: $1,865.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $28,016.10\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $0.00\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_2 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 30}, \"employment_income\": {2025: 20_000}},\n",
+ " \"child\": {\"age\": {2025: 5}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_2 = Simulation(situation=situation_2)\n",
+ "reform_2 = Simulation(situation=situation_2, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 2: Single Parent with 5-year-old, $20k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_2.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_2.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_2.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_2.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_2.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_2.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_2.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_2.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_2.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_2.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_2.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_2.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_2.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_2.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_2.calculate('household_net_income', 2025)[0] - baseline_2.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 3: Married Couple with Infant (Should Benefit)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 3: Married Couple with Infant (age 0), $15k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $4,328.00\n",
+ "UT EITC (20% of federal): $865.60\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $675.00\n",
+ " UT non-refundable credits: $1,965.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $49,530.96\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: True\n",
+ " UT refundable EITC: $865.60\n",
+ " UT non-refundable EITC: $0.00\n",
+ " UT non-refundable credits: $1,100.00\n",
+ " UT refundable credits: $865.60\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $-865.60\n",
+ " Household net income: $50,396.56\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $865.60\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_3 = {\n",
+ " \"people\": {\n",
+ " \"parent1\": {\"age\": {2025: 25}, \"employment_income\": {2025: 15_000}},\n",
+ " \"parent2\": {\"age\": {2025: 26}, \"employment_income\": {2025: 0}},\n",
+ " \"baby\": {\"age\": {2025: 0}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent1\", \"parent2\", \"baby\"]}},\n",
+ " \"families\": {\"family\": {\"members\": [\"parent1\", \"parent2\", \"baby\"]}},\n",
+ " \"marital_units\": {\"marital_unit\": {\"members\": [\"parent1\", \"parent2\"]}},\n",
+ " \"spm_units\": {\"spm_unit\": {\"members\": [\"parent1\", \"parent2\", \"baby\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent1\", \"parent2\", \"baby\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_3 = Simulation(situation=situation_3)\n",
+ "reform_3 = Simulation(situation=situation_3, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 3: Married Couple with Infant (age 0), $15k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_3.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_3.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_3.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_3.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_3.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_3.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_3.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_3.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_3.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_3.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_3.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_3.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_3.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_3.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_3.calculate('household_net_income', 2025)[0] - baseline_3.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 4: Mixed Ages - One Qualifying, One Not (Should Benefit)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 4: Single Parent with kids age 1 and 7, $25k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $6,804.51\n",
+ "UT EITC (20% of federal): $1,360.90\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $1,125.00\n",
+ " UT non-refundable credits: $2,360.90\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $59,971.83\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: True\n",
+ " UT refundable EITC: $1,360.90\n",
+ " UT non-refundable EITC: $0.00\n",
+ " UT non-refundable credits: $1,000.00\n",
+ " UT refundable credits: $1,360.90\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $-1,360.90\n",
+ " Household net income: $61,332.73\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $1,360.91\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_4 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 32}, \"employment_income\": {2025: 25_000}},\n",
+ " \"child1\": {\"age\": {2025: 1}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " \"child2\": {\"age\": {2025: 7}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child1\", \"child2\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child1\", \"child2\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_4 = Simulation(situation=situation_4)\n",
+ "reform_4 = Simulation(situation=situation_4, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 4: Single Parent with kids age 1 and 7, $25k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_4.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_4.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_4.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_4.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_4.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_4.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_4.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_4.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_4.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_4.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_4.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_4.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_4.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_4.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_4.calculate('household_net_income', 2025)[0] - baseline_4.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 5: Child at Age Boundary (age 2 - Should Benefit)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 5: Single Parent with child age 2, $18k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $4,328.00\n",
+ "UT EITC (20% of federal): $865.60\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $810.00\n",
+ " UT non-refundable credits: $1,865.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $47,112.42\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: True\n",
+ " UT refundable EITC: $865.60\n",
+ " UT non-refundable EITC: $0.00\n",
+ " UT non-refundable credits: $1,000.00\n",
+ " UT refundable credits: $865.60\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $-865.60\n",
+ " Household net income: $47,978.02\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $865.60\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_5 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 29}, \"employment_income\": {2025: 18_000}},\n",
+ " \"child\": {\"age\": {2025: 2}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_5 = Simulation(situation=situation_5)\n",
+ "reform_5 = Simulation(situation=situation_5, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 5: Single Parent with child age 2, $18k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_5.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_5.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_5.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_5.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_5.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_5.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_5.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_5.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_5.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_5.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_5.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_5.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_5.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_5.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_5.calculate('household_net_income', 2025)[0] - baseline_5.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 6: Child Just Over Age Boundary (age 3 - Should NOT Benefit)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 6: Single Parent with child age 3, $18k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $4,328.00\n",
+ "UT EITC (20% of federal): $865.60\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $810.00\n",
+ " UT non-refundable credits: $1,865.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $44,659.99\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: False\n",
+ " UT refundable EITC: $0.00\n",
+ " UT non-refundable EITC: $865.60\n",
+ " UT non-refundable credits: $1,865.60\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $44,659.99\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $0.00\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_6 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 29}, \"employment_income\": {2025: 18_000}},\n",
+ " \"child\": {\"age\": {2025: 3}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_6 = Simulation(situation=situation_6)\n",
+ "reform_6 = Simulation(situation=situation_6, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 6: Single Parent with child age 3, $18k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_6.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_6.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_6.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_6.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_6.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_6.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_6.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_6.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_6.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_6.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_6.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_6.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_6.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_6.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_6.calculate('household_net_income', 2025)[0] - baseline_6.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 7: Childless Adult (Should NOT Benefit)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 7: Childless Adult, $12k income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $543.43\n",
+ "UT EITC (20% of federal): $108.69\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $540.00\n",
+ " UT non-refundable credits: $108.69\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $13,006.33\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: False\n",
+ " UT refundable EITC: $0.00\n",
+ " UT non-refundable EITC: $108.69\n",
+ " UT non-refundable credits: $108.69\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $13,006.33\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $0.00\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_7 = {\n",
+ " \"people\": {\n",
+ " \"adult\": {\"age\": {2025: 35}, \"employment_income\": {2025: 12_000}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"adult\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"adult\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_7 = Simulation(situation=situation_7)\n",
+ "reform_7 = Simulation(situation=situation_7, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 7: Childless Adult, $12k income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_7.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_7.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_7.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_7.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_7.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_7.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_7.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_7.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_7.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_7.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_7.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_7.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_7.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_7.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_7.calculate('household_net_income', 2025)[0] - baseline_7.calculate('household_net_income', 2025)[0]:,.2f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 8: Qualifying Child but NO Income (Should NOT Benefit)\n",
+ "\n",
+ "Even with a refundable EITC, households with no earned income should get $0 because the EITC phases in with income. This verifies we're only making the existing credit refundable, not creating a new credit."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 8: Single Parent with 1-year-old, $0 income\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $0.00\n",
+ "UT EITC (20% of federal): $0.00\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $0.00\n",
+ " UT non-refundable credits: $1,000.00\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $28,042.52\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: True\n",
+ " UT refundable EITC: $0.00\n",
+ " UT non-refundable EITC: $0.00\n",
+ " UT non-refundable credits: $1,000.00\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $28,042.52\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $0.00\n",
+ "\n",
+ "*** Key check: Federal EITC = $0 because EITC phases in with earned income ***\n",
+ "*** Therefore UT EITC = 20% * $0 = $0, and refundable EITC = $0 ***\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_8 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 28}, \"employment_income\": {2025: 0}},\n",
+ " \"child\": {\"age\": {2025: 1}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_8 = Simulation(situation=situation_8)\n",
+ "reform_8 = Simulation(situation=situation_8, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 8: Single Parent with 1-year-old, $0 income\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_8.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_8.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_8.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_8.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_8.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_8.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_8.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_8.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_8.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_8.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_8.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_8.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_8.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_8.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_8.calculate('household_net_income', 2025)[0] - baseline_8.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n*** Key check: Federal EITC = $0 because EITC phases in with earned income ***\")\n",
+ "print(f\"*** Therefore UT EITC = 20% * $0 = $0, and refundable EITC = $0 ***\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Example 9: Qualifying Child with $5k Income (Should Benefit - Partial EITC)\n",
+ "\n",
+ "With $5k income, the EITC is in the phase-in range. This household should benefit since they get a partial federal EITC that becomes refundable."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "======================================================================\n",
+ "EXAMPLE 9: Single Parent with 1-year-old, $5k income (phase-in)\n",
+ "======================================================================\n",
+ "\n",
+ "Federal EITC: $1,700.00\n",
+ "UT EITC (20% of federal): $340.00\n",
+ "\n",
+ "Baseline (non-refundable):\n",
+ " UT income tax before credits: $225.00\n",
+ " UT non-refundable credits: $1,340.00\n",
+ " UT refundable credits: $0.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $0.00\n",
+ " Household net income: $34,275.12\n",
+ "\n",
+ "Reform (refundable for age <= 2):\n",
+ " Has qualifying child: True\n",
+ " UT refundable EITC: $340.00\n",
+ " UT non-refundable EITC: $0.00\n",
+ " UT non-refundable credits: $1,000.00\n",
+ " UT refundable credits: $340.00\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Invalid values for enum StateGroup: ['UT']. These will be encoded as index 0.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " UT income tax: $-340.00\n",
+ " Household net income: $34,615.12\n",
+ "\n",
+ ">>> BENEFIT FROM REFORM: $340.00\n",
+ "\n",
+ "*** At $5k income, federal EITC is in phase-in range ***\n",
+ "*** UT EITC = 20% of federal, and this becomes refundable ***\n"
+ ]
+ }
+ ],
+ "source": [
+ "situation_9 = {\n",
+ " \"people\": {\n",
+ " \"parent\": {\"age\": {2025: 28}, \"employment_income\": {2025: 5_000}},\n",
+ " \"child\": {\"age\": {2025: 1}, \"is_tax_unit_dependent\": {2025: True}},\n",
+ " },\n",
+ " \"tax_units\": {\"tax_unit\": {\"members\": [\"parent\", \"child\"]}},\n",
+ " \"households\": {\"household\": {\"members\": [\"parent\", \"child\"], \"state_code\": {2025: \"UT\"}}},\n",
+ "}\n",
+ "\n",
+ "baseline_9 = Simulation(situation=situation_9)\n",
+ "reform_9 = Simulation(situation=situation_9, reform=create_reform())\n",
+ "\n",
+ "print(\"=\"*70)\n",
+ "print(\"EXAMPLE 9: Single Parent with 1-year-old, $5k income (phase-in)\")\n",
+ "print(\"=\"*70)\n",
+ "print(f\"\\nFederal EITC: ${baseline_9.calculate('eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"UT EITC (20% of federal): ${baseline_9.calculate('ut_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nBaseline (non-refundable):\")\n",
+ "print(f\" UT income tax before credits: ${baseline_9.calculate('ut_income_tax_before_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${baseline_9.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${baseline_9.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${baseline_9.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${baseline_9.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\nReform (refundable for age <= 2):\")\n",
+ "print(f\" Has qualifying child: {reform_9.calculate('ut_has_qualifying_child_for_refundable_eitc', 2025)[0]}\")\n",
+ "print(f\" UT refundable EITC: ${reform_9.calculate('ut_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable EITC: ${reform_9.calculate('ut_non_refundable_eitc', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT non-refundable credits: ${reform_9.calculate('ut_non_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT refundable credits: ${reform_9.calculate('ut_refundable_credits', 2025)[0]:,.2f}\")\n",
+ "print(f\" UT income tax: ${reform_9.calculate('ut_income_tax', 2025)[0]:,.2f}\")\n",
+ "print(f\" Household net income: ${reform_9.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n>>> BENEFIT FROM REFORM: ${reform_9.calculate('household_net_income', 2025)[0] - baseline_9.calculate('household_net_income', 2025)[0]:,.2f}\")\n",
+ "print(f\"\\n*** At $5k income, federal EITC is in phase-in range ***\")\n",
+ "print(f\"*** UT EITC = 20% of federal, and this becomes refundable ***\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Summary Table"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "==========================================================================================\n",
+ "SUMMARY: UT Refundable EITC Household Examples\n",
+ "==========================================================================================\n",
+ " Example Fed EITC UT EITC Refundable Benefit Status\n",
+ " 1: Child age 1, $20k $4,328 $866 $866 $865.60 PASS\n",
+ " 2: Child age 5, $20k $4,328 $866 $0 $0.00 PASS\n",
+ " 3: Infant age 0, $15k $4,328 $866 $866 $865.60 PASS\n",
+ "4: Kids age 1 & 7, $25k $6,805 $1,361 $1,361 $1,360.91 PASS\n",
+ " 5: Child age 2, $18k $4,328 $866 $866 $865.60 PASS\n",
+ " 6: Child age 3, $18k $4,328 $866 $0 $0.00 PASS\n",
+ " 7: Childless, $12k $543 $109 $0 $0.00 PASS\n",
+ " 8: Child age 1, $0 $0 $0 $0 $0.00 PASS\n",
+ " 9: Child age 1, $5k $1,700 $340 $340 $340.00 PASS\n",
+ "==========================================================================================\n",
+ "\n",
+ "All tests passed: True\n",
+ "\n",
+ "----------------------------------------------------------------------\n",
+ "KEY INSIGHT - EITC Phase-in Verification:\n",
+ "----------------------------------------------------------------------\n",
+ "Example 8 ($0 income): Fed EITC = $0, Benefit = $0\n",
+ "Example 9 ($5k income): Fed EITC phases in, Benefit > $0\n",
+ "\n",
+ "This confirms the reform only makes the EXISTING credit refundable.\n",
+ "The EITC phase-in structure is preserved.\n",
+ "----------------------------------------------------------------------\n"
+ ]
+ }
+ ],
+ "source": [
+ "examples = [\n",
+ " (\"1: Child age 1, $20k\", baseline_1, reform_1, True),\n",
+ " (\"2: Child age 5, $20k\", baseline_2, reform_2, False),\n",
+ " (\"3: Infant age 0, $15k\", baseline_3, reform_3, True),\n",
+ " (\"4: Kids age 1 & 7, $25k\", baseline_4, reform_4, True),\n",
+ " (\"5: Child age 2, $18k\", baseline_5, reform_5, True),\n",
+ " (\"6: Child age 3, $18k\", baseline_6, reform_6, False),\n",
+ " (\"7: Childless, $12k\", baseline_7, reform_7, False),\n",
+ " (\"8: Child age 1, $0\", baseline_8, reform_8, False),\n",
+ " (\"9: Child age 1, $5k\", baseline_9, reform_9, True),\n",
+ "]\n",
+ "\n",
+ "summary_data = []\n",
+ "for desc, baseline, reform, expected_benefit in examples:\n",
+ " baseline_income = baseline.calculate('household_net_income', 2025)[0]\n",
+ " reform_income = reform.calculate('household_net_income', 2025)[0]\n",
+ " benefit = reform_income - baseline_income\n",
+ " federal_eitc = baseline.calculate('eitc', 2025)[0]\n",
+ " ut_eitc = baseline.calculate('ut_eitc', 2025)[0]\n",
+ " refundable_eitc = reform.calculate('ut_refundable_eitc', 2025)[0]\n",
+ " actual_benefit = benefit > 0.5\n",
+ " status = \"PASS\" if actual_benefit == expected_benefit else \"FAIL\"\n",
+ " \n",
+ " summary_data.append({\n",
+ " \"Example\": desc,\n",
+ " \"Fed EITC\": f\"${federal_eitc:,.0f}\",\n",
+ " \"UT EITC\": f\"${ut_eitc:,.0f}\",\n",
+ " \"Refundable\": f\"${refundable_eitc:,.0f}\",\n",
+ " \"Benefit\": f\"${benefit:,.2f}\",\n",
+ " \"Status\": status,\n",
+ " })\n",
+ "\n",
+ "df_summary = pd.DataFrame(summary_data)\n",
+ "print(\"=\"*90)\n",
+ "print(\"SUMMARY: UT Refundable EITC Household Examples\")\n",
+ "print(\"=\"*90)\n",
+ "print(df_summary.to_string(index=False))\n",
+ "print(\"=\"*90)\n",
+ "\n",
+ "all_pass = all(row[\"Status\"] == \"PASS\" for row in summary_data)\n",
+ "print(f\"\\nAll tests passed: {all_pass}\")\n",
+ "\n",
+ "print(\"\\n\" + \"-\"*70)\n",
+ "print(\"KEY INSIGHT - EITC Phase-in Verification:\")\n",
+ "print(\"-\"*70)\n",
+ "print(\"Example 8 ($0 income): Fed EITC = $0, Benefit = $0\")\n",
+ "print(\"Example 9 ($5k income): Fed EITC phases in, Benefit > $0\")\n",
+ "print(\"\\nThis confirms the reform only makes the EXISTING credit refundable.\")\n",
+ "print(\"The EITC phase-in structure is preserved.\")\n",
+ "print(\"-\"*70)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Summary table exported to: ut_refundable_eitc_summary.csv\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Export summary table to CSV\n",
+ "df_summary.to_csv(\"ut_refundable_eitc_summary.csv\", index=False)\n",
+ "print(f\"Summary table exported to: ut_refundable_eitc_summary.csv\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/us/states/ut/ut_refundable_eitc_summary.csv b/us/states/ut/ut_refundable_eitc_summary.csv
new file mode 100644
index 0000000..1b9dcb2
--- /dev/null
+++ b/us/states/ut/ut_refundable_eitc_summary.csv
@@ -0,0 +1,10 @@
+Example,Fed EITC,UT EITC,Refundable,Benefit,Status
+"1: Child age 1, $20k","$4,328",$866,$866,$865.60,PASS
+"2: Child age 5, $20k","$4,328",$866,$0,$0.00,PASS
+"3: Infant age 0, $15k","$4,328",$866,$866,$865.60,PASS
+"4: Kids age 1 & 7, $25k","$6,805","$1,361","$1,361","$1,360.91",PASS
+"5: Child age 2, $18k","$4,328",$866,$866,$865.60,PASS
+"6: Child age 3, $18k","$4,328",$866,$0,$0.00,PASS
+"7: Childless, $12k",$543,$109,$0,$0.00,PASS
+"8: Child age 1, $0",$0,$0,$0,$0.00,PASS
+"9: Child age 1, $5k","$1,700",$340,$340,$340.00,PASS