Skip to content

Commit fedd756

Browse files
hmgaudeckerclaude
andcommitted
Rename consumption_unequiv → consumption_dollars; tighten types; drop factory magic
- consumption_unequiv → consumption_dollars (state, action, params, module, test module). The dollar / dollars suffix replaces the unequiv / equiv pair on the in-$ side; `consumption_equiv` (the utility-equivalized form) keeps its name. - consumption_dollar_grid.py → consumption_dollars_grid.py. - `_DERIVED_CATEGORICALS` dicts now include `target_his` alongside `his`, `good_health`, `is_married`, `pref_type`. The previous `BASE_DERIVED_CATEGORICALS` constant + per-factory merge is gone — callers pass the full dict. - `RegimeSpec` TypedDict fields tightened to `Literal[...]` for the four axes. - `fixed_params` annotations switched to `lcm.typing.UserParams` (the pylcm-side alias) across `create_model`, `build_all_regimes`, `build_grids`. - `u_working_life` → `u_can_work`; `u_retired` → `u_cannot_work`. - `_build_per_target_regime_next_assets` → `_build_per_target_regime_assets`; ordering of dispatch site and definition aligned (assets → health → claimed_ss → lagged_labor_supply). `lagged_supply_transition` → `lagged_labor_supply_transition`. - `MAX_CONSUMPTION_DOLLARS` docstring: drop the in-line rationale, add a TODO referencing pylcm#348. - `aca.create_model` return doc → "pylcm Model" (no "ACA-specific" qualifier). - CI: pylcm pin uses `@main` (PyPI release lags so the git pin stays). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2779011 commit fedd756

22 files changed

Lines changed: 169 additions & 179 deletions

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ jobs:
2626
- uses: actions/setup-python@v6
2727
with:
2828
python-version: ${{ matrix.python-version }}
29-
- name: Install pylcm from main (PyPI release lags)
29+
- name: Install pylcm
3030
run: >-
3131
pip install "pylcm @
32-
git+https://github.com/OpenSourceEconomics/pylcm.git@99a5e31"
32+
git+https://github.com/OpenSourceEconomics/pylcm.git@main"
3333
- name: Install aca-model with test deps
3434
run: pip install -e . pytest pdbp
3535
- name: Run pytest
0 Bytes
Binary file not shown.

src/aca_model/aca/model.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
from typing import Any
99

1010
from lcm import AgeGrid, DiscreteGrid, Model
11+
from lcm.typing import UserParams
1112

1213
from aca_model.aca import PolicyVariant
1314
from aca_model.aca.regimes import build_all_regimes
14-
from aca_model.baseline.derived_categoricals import BASE_DERIVED_CATEGORICALS
1515
from aca_model.baseline.regimes import RegimeId
1616
from aca_model.config import MODEL_CONFIG, GridConfig
1717

@@ -20,7 +20,7 @@ def create_model(
2020
*,
2121
n_subjects: int,
2222
policy: PolicyVariant,
23-
fixed_params: Mapping[str, Any],
23+
fixed_params: UserParams,
2424
wage_params: Mapping[str, Any],
2525
derived_categoricals: Mapping[str, DiscreteGrid],
2626
grid_config: GridConfig,
@@ -39,14 +39,15 @@ def create_model(
3939
`log_ft_wage_std`, `adj_wage_hours_*`) used only at grid-build
4040
time to size the assets-floor to `-max_annual_labor_income`.
4141
Not routed to the pylcm Model.
42-
derived_categoricals: Extra categorical mappings for derived
43-
variables not in the model's state/action grids. `target_his`
44-
is added automatically via `BASE_DERIVED_CATEGORICALS`.
42+
derived_categoricals: Categorical mappings for `pd.Series`
43+
fixed_params index levels that aren't model state/action
44+
grids — `target_his`, `his`, `good_health`, `is_married`,
45+
`pref_type`.
4546
grid_config: Continuous-grid point counts.
4647
pref_type_grid: Pref-type `DiscreteGrid`.
4748
4849
Returns:
49-
pylcm Model with ACA-specific function overrides.
50+
pylcm Model.
5051
5152
"""
5253
ages = AgeGrid(
@@ -68,6 +69,6 @@ def create_model(
6869
regime_id_class=RegimeId,
6970
description=f"Structural retirement model ({policy.name})",
7071
fixed_params=fixed_params,
71-
derived_categoricals={**BASE_DERIVED_CATEGORICALS, **derived_categoricals},
72+
derived_categoricals=derived_categoricals,
7273
n_subjects=n_subjects,
7374
)

src/aca_model/aca/regimes/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Any
66

77
from lcm import DiscreteGrid, Regime
8+
from lcm.typing import UserParams
89

910
from aca_model.aca.health_insurance import PolicyVariant
1011
from aca_model.aca.regimes._overrides import apply_aca_overrides
@@ -17,7 +18,7 @@ def build_all_regimes(
1718
*,
1819
policy: PolicyVariant,
1920
grid_config: GridConfig,
20-
fixed_params: Mapping[str, Any],
21+
fixed_params: UserParams,
2122
wage_params: Mapping[str, Any],
2223
pref_type_grid: DiscreteGrid,
2324
) -> dict[str, Regime]:

src/aca_model/agent/assets_and_income.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def cash_on_hand(
3535
return assets + after_tax_income + ssi_benefit - hic_premium
3636

3737

38-
def consumption_unequiv_floor(
38+
def consumption_dollars_floor(
3939
consumption_equiv_floor: float,
4040
equivalence_scale: FloatND,
4141
) -> FloatND:
@@ -45,17 +45,17 @@ def consumption_unequiv_floor(
4545

4646
def transfers(
4747
cash_on_hand: FloatND,
48-
consumption_unequiv_floor: FloatND,
48+
consumption_dollars_floor: FloatND,
4949
) -> FloatND:
5050
"""Government transfers to enforce the consumption floor."""
51-
return jnp.maximum(0.0, consumption_unequiv_floor - cash_on_hand)
51+
return jnp.maximum(0.0, consumption_dollars_floor - cash_on_hand)
5252

5353

5454
def next_assets(
5555
cash_on_hand: FloatND,
5656
transfers: FloatND,
5757
pension_assets_adjustment: FloatND,
58-
consumption_unequiv: ContinuousAction,
58+
consumption_dollars: ContinuousAction,
5959
oop_costs: FloatND,
6060
) -> ContinuousState:
6161
"""Compute beginning-of-next-period assets for non-terminal targets.
@@ -67,15 +67,15 @@ def next_assets(
6767
cash_on_hand
6868
+ transfers
6969
+ pension_assets_adjustment
70-
- consumption_unequiv
70+
- consumption_dollars
7171
- oop_costs
7272
)
7373

7474

7575
def next_assets_when_dead(
7676
cash_on_hand: FloatND,
7777
transfers: FloatND,
78-
consumption_unequiv: ContinuousAction,
78+
consumption_dollars: ContinuousAction,
7979
oop_costs: FloatND,
8080
) -> ContinuousState:
8181
"""Compute beginning-of-next-period assets for the dead/terminal target.
@@ -86,17 +86,17 @@ def next_assets_when_dead(
8686
(which would otherwise need to come from a transition `dead` does not
8787
have, since `aime` is not a state in the terminal regime).
8888
"""
89-
return cash_on_hand + transfers - consumption_unequiv - oop_costs
89+
return cash_on_hand + transfers - consumption_dollars - oop_costs
9090

9191

9292
def borrowing_constraint(
93-
consumption_unequiv: ContinuousAction,
93+
consumption_dollars: ContinuousAction,
9494
cash_on_hand: FloatND,
95-
consumption_unequiv_floor: FloatND,
95+
consumption_dollars_floor: FloatND,
9696
) -> BoolND:
9797
"""Consumption cannot exceed post-transfer resources.
9898
99-
Post-transfer resources are `max(cash_on_hand, consumption_unequiv_floor)`:
99+
Post-transfer resources are `max(cash_on_hand, consumption_dollars_floor)`:
100100
the transfer system tops `cash_on_hand` to the floor when below,
101101
otherwise resources are unchanged. The algebraic identity is
102102
`cash_on_hand + transfers == max(cash_on_hand, floor)`; the `max`
@@ -105,4 +105,4 @@ def borrowing_constraint(
105105
the kink-boundary comparison at large negative values of `assets`.
106106
The `max` form returns `floor` exactly.
107107
"""
108-
return consumption_unequiv <= jnp.maximum(cash_on_hand, consumption_unequiv_floor)
108+
return consumption_dollars <= jnp.maximum(cash_on_hand, consumption_dollars_floor)

src/aca_model/agent/preferences.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,14 @@ def leisure_retired(
122122

123123

124124
def consumption_equiv(
125-
consumption_unequiv: ContinuousAction,
125+
consumption_dollars: ContinuousAction,
126126
equivalence_scale: FloatND,
127127
) -> FloatND:
128128
"""Utility-equivalized consumption."""
129-
return consumption_unequiv / equivalence_scale
129+
return consumption_dollars / equivalence_scale
130130

131131

132-
def u_working_life(
132+
def u_can_work(
133133
consumption_equiv: FloatND,
134134
leisure: FloatND,
135135
consumption_weight: FloatND,
@@ -152,7 +152,7 @@ def u_working_life(
152152
return u * utility_scale_factor
153153

154154

155-
def u_retired(
155+
def u_cannot_work(
156156
consumption_equiv: FloatND,
157157
good_health: IntND,
158158
consumption_weight: FloatND,
@@ -167,7 +167,7 @@ def u_retired(
167167
time_endowment=time_endowment,
168168
leisure_cost_of_bad_health=leisure_cost_of_bad_health,
169169
)
170-
return u_working_life(
170+
return u_can_work(
171171
consumption_equiv=consumption_equiv,
172172
leisure=leisure,
173173
consumption_weight=consumption_weight,
@@ -233,7 +233,7 @@ def discount_factor(
233233

234234

235235
def utility_scale_factor(
236-
average_consumption_unequiv: float,
236+
average_consumption_dollars: float,
237237
consumption_weight: FloatND,
238238
coefficient_rra: FloatND,
239239
time_endowment: float,
@@ -242,7 +242,7 @@ def utility_scale_factor(
242242
) -> FloatND:
243243
"""Compute the scale factor so utility is approximately 1 at typical values."""
244244
average_leisure = time_endowment - reference_hours - fixed_cost_of_work_intercept
245-
u_cons = average_consumption_unequiv**consumption_weight
245+
u_cons = average_consumption_dollars**consumption_weight
246246
u_leisure = average_leisure ** (1.0 - consumption_weight)
247247

248248
one_minus_rra = jnp.where(

src/aca_model/baseline/derived_categoricals.py

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/aca_model/baseline/model.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
from typing import Any
1515

1616
from lcm import AgeGrid, DiscreteGrid, Model
17+
from lcm.typing import UserParams
1718

18-
from aca_model.baseline.derived_categoricals import BASE_DERIVED_CATEGORICALS
1919
from aca_model.baseline.regimes import RegimeId, build_all_regimes
2020
from aca_model.config import MODEL_CONFIG, GridConfig
2121

2222

2323
def create_model(
2424
*,
2525
n_subjects: int,
26-
fixed_params: Mapping[str, Any],
26+
fixed_params: UserParams,
2727
wage_params: Mapping[str, Any],
2828
derived_categoricals: Mapping[str, DiscreteGrid],
2929
grid_config: GridConfig,
@@ -42,11 +42,10 @@ def create_model(
4242
`log_ft_wage_std`, `adj_wage_hours_*`) used only at grid-build
4343
time to size the assets-floor to `-max_annual_labor_income`.
4444
Not routed to the pylcm Model.
45-
derived_categoricals: Extra categorical mappings for derived
46-
variables not in the model's state/action grids. Needed when
47-
`fixed_params` contains `pd.Series` indexed by DAG function
48-
outputs. `target_his` is added automatically via
49-
`BASE_DERIVED_CATEGORICALS`.
45+
derived_categoricals: Categorical mappings for `pd.Series`
46+
fixed_params index levels that aren't model state/action
47+
grids — `target_his`, `his`, `good_health`, `is_married`,
48+
`pref_type`.
5049
grid_config: Continuous-grid point counts. Pass `GRID_CONFIG` for
5150
production values or `BENCHMARK_GRID_CONFIG` for the
5251
fast-but-structurally-faithful benchmark.
@@ -77,6 +76,6 @@ def create_model(
7776
regime_id_class=RegimeId,
7877
description="Baseline structural retirement model (pre-ACA)",
7978
fixed_params=fixed_params,
80-
derived_categoricals={**BASE_DERIVED_CATEGORICALS, **derived_categoricals},
79+
derived_categoricals=derived_categoricals,
8180
n_subjects=n_subjects,
8281
)

src/aca_model/baseline/regimes/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from typing import Any
1515

1616
from lcm import DiscreteGrid, Regime
17+
from lcm.typing import UserParams
1718

1819
from aca_model.baseline.regimes import _nongroup as nongroup
1920
from aca_model.baseline.regimes import _retiree as retiree
@@ -60,7 +61,7 @@ def build_regime(name: str, grids: Grids) -> Regime:
6061
def build_all_regimes(
6162
*,
6263
grid_config: GridConfig,
63-
fixed_params: Mapping[str, Any],
64+
fixed_params: UserParams,
6465
wage_params: Mapping[str, Any],
6566
pref_type_grid: DiscreteGrid,
6667
) -> dict[str, Regime]:

0 commit comments

Comments
 (0)