Summary
Inside a templated alias body, a state subscript that mixes bare LHS-template placeholders with =-bound apply_along coords is destructively rewritten to a per-cell name, dropping the bound parts.
Repro
Spec snippet (per-loc force-of-infection, no spatial coupling):
state:
- X[age, vax, loc, imm]
- I1[age, vax, loc]
...
aliases:
foi[age, loc]: "apply_along(vax=v,
I1[loc, age=ap, vax=v]
+ apply_along(imm=k, X[loc, age=ap, vax=v, imm=k]))"
transitions:
- {from: "X[age, vax, loc, imm]", to: "E[age, vax, loc]",
rate: "foi[age, loc] * theta[imm]"}
age is the templated LHS axis used as the bound apply_along coord (age=ap); loc is the LHS template wildcard. At alias expansion time the body's X[loc, age=ap, vax=v, imm=k] is fed to _apply_template_substitutions._inline_replacer:
phs = [p.strip() for p in inner.split(",") if p.strip() and "=" not in p] # ["loc"]
...
return _render_template_name(inner_base, phs, assignment) # "X__loc_AK"
The =-bound parts (age=ap, vax=v, imm=k) are filtered out, then the bare placeholder collapses the whole subscript to X__loc_AK. Downstream this surfaces as a missing parameter, e.g. KeyError: "Required parameter 'X__age_age0to17__vax_unvaccinated__imm_x0__loc_AK' was requested but not configured."
Expected
The mixed-mode subscript should be rewritten to a canonical literal-cell selector that the regular apply_along/vectorize path already handles:
X[loc=AK, age=ap, vax=v, imm=k]
i.e. substitute each bare placeholder with its axis=coord binding from the LHS row assignment, preserve every =-bound entry verbatim, and let downstream resolve cell indices.
Scope
src/op_system/_templates.py::_apply_template_substitutions._inline_replacer — when bound entries are present alongside bare placeholders, switch to binding-rewrite instead of name-collapse.
- Same path for shaped params is already correct (literal-index emission); leave shaped branch untouched.
- Add a regression test in
tests/op_system/test_op_system_specs.py covering the mixed case.
Related
Summary
Inside a templated alias body, a state subscript that mixes bare LHS-template placeholders with
=-boundapply_alongcoords is destructively rewritten to a per-cell name, dropping the bound parts.Repro
Spec snippet (per-loc force-of-infection, no spatial coupling):
ageis the templated LHS axis used as the bound apply_along coord (age=ap);locis the LHS template wildcard. At alias expansion time the body'sX[loc, age=ap, vax=v, imm=k]is fed to_apply_template_substitutions._inline_replacer:The
=-bound parts (age=ap,vax=v,imm=k) are filtered out, then the bare placeholder collapses the whole subscript toX__loc_AK. Downstream this surfaces as a missing parameter, e.g.KeyError: "Required parameter 'X__age_age0to17__vax_unvaccinated__imm_x0__loc_AK' was requested but not configured."Expected
The mixed-mode subscript should be rewritten to a canonical literal-cell selector that the regular
apply_along/vectorize path already handles:i.e. substitute each bare placeholder with its
axis=coordbinding from the LHS row assignment, preserve every=-bound entry verbatim, and let downstream resolve cell indices.Scope
src/op_system/_templates.py::_apply_template_substitutions._inline_replacer— when bound entries are present alongside bare placeholders, switch to binding-rewrite instead of name-collapse.tests/op_system/test_op_system_specs.pycovering the mixed case.Related
lhs_assignmentthrough_expand_helpersfor shaped same-axis-twice in templated aliases) — same end of the pipeline.