Skip to content

Fix invalid vars#4827

Draft
cmhyett wants to merge 3 commits into
SciML:masterfrom
cmhyett:fix-invalid-vars
Draft

Fix invalid vars#4827
cmhyett wants to merge 3 commits into
SciML:masterfrom
cmhyett:fix-invalid-vars

Conversation

@cmhyett

@cmhyett cmhyett commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Builds on #4826, but solves a very narrow problem.
invalid_variables incorrectly flags array variables as invalid, when they are very clearly in the system. Code changes mimicked the array handling in unassignable_variables

Checklist

  • Appropriate tests were added
  • Any code changes were done in a way that does not break public API
  • All documentation related to code changes were updated
  • The new code follows the
    contributor guidelines, in particular the SciML Style Guide and
    COLPRAC.
  • Any new documentation only uses public API

Additional context

Add any other context about the problem here.

cmhyett and others added 3 commits July 23, 2026 20:17
`mtkcompile`'s zero-variable elimination moves variables with trivial
dynamics (e.g. `D(x) ~ 0`) out of the unknowns, rewriting them as an
observed polynomial in the independent variable with a `missing`-bound
constant-of-integration parameter. This ignored discrete/continuous
events: a variable a callback impulsively modifies is no longer an
unknown, so a functional (`ImperativeAffect`) kick errors at `ODEProblem`
construction ("... refers to missing variable(s) ... reduced away").

Fix it two ways:

- Auto-detect (default): add `variables_modified_by_events(sys)` in
  ModelingToolkitBase and extend `__eliminate_zero_variables!` to protect
  event-modified variables using the same seam that already retains
  `irreducible` variables. Such a variable stays an ordinary numerically
  integrated unknown; unrelated trivial dynamics are still integrated.
- Opt-out flag: `mtkcompile(sys; analytic_integration=false)` disables the
  transformation wholesale (threaded to `eliminate_mm_zeros`, composed via
  AND so the SDE force-off still wins).

Add a regression testset covering equational and imperative kicks, the
flag, selective protection, and the event-free no-regression case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`invalid_variables` (the observed-side check in `compile_functional_affect`)
did a naive `setdiff!(search_variables(expr), all_symbols(sys))` with no
handling for array symbolics. An array-valued observed handle — e.g. binding
an array variable, or a vector of array handles in a reduce-style affect —
surfaces as the bare array symbolic `x(t)`, but a flattened system stores it
as its scalarized elements `x(t)[i]`, so the bare symbol matched nothing and a
valid affect was rejected with "refers to missing variable(s)".

Mirror the modified-side `unassignable_variables`: accept the whole-array
symbol if present, otherwise walk `stable_eachindex` and check each scalar
element. This removes the observed/modified asymmetry — the modified path
already accepted array-valued handles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The array-awareness added to `invalid_variables` checked membership against
`all_symbols(sys)` directly, but that returns a `Vector` — so `var in valid`
used symbolic `==` and errored with "non-boolean used in boolean context"
for every affect with an `observed` clause (scalar or array), breaking even
existing scalar-observed callbacks.

Mirror `unassignable_variables` properly: build a `Set{SymbolicT}` of valid
symbols (scalarizing array symbols into elements) so membership uses
`isequal`/hashing and returns `Bool`, then scalarize array variables on the
lookup side too.

Add a `symbolic_events.jl` testset covering an `ImperativeAffect` whose
`observed` clause reads a whole array-valued variable (builds, solves, and
records the array), plus unit checks that `invalid_variables` accepts a
whole array and a present scalar while still flagging a genuinely missing
variable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant