Skip to content

Give generated symbols deterministic names - #180

Merged
ChrisRackauckas merged 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:fix/deterministic-generated-names
Sep 7, 2026
Merged

ChrisRackauckas merged 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:fix/deterministic-generated-names

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member

Ignore this PR until reviewed by @ChrisRackauckas.

Closes #28.

deim named the reduced state and its array parameters with gensym, so every reduction produced fresh names. Two reductions of the same system therefore built different symbolic expressions, which meant different RuntimeGeneratedFunctions and a full recompile of the problem, the residual, and the reconstruction each time. Names are now built from a fixed base plus GENERATED_SUFFIX, which is ˍmor — the ˍ is U+02CD, the modifier letter ModelingToolkit already uses for generated names such as xˍt, so it is outside the space of names a user would type.

Because the names are now shared rather than unique, the source system's own names have to be avoided. _reserved_names collects the names the reduced system inherits (kept parameters, source field variables, preserved observed left-hand sides) and _generated_name appends a counter when the base is taken. That case is reached by reducing an already-reduced model, whose parameters are named Aˍmor, Cˍmor and so on.

Failing before, passing after

Reducing the same system twice, on main at 2439bac:

first ROM state name:  ##ŷ#294
second ROM state name: ##ŷ#315
names equal:     false
equations equal: false
observed equal:  false

Same script on this branch:

first ROM state name:  ŷˍmor
second ROM state name: ŷˍmor
names equal:     true
equations equal: true
observed equal:  true

The new deterministic generated names testset in test/array_structure.jl asserts the equal-equations and equal-parameters property, which is what makes the generated code shared; the generated names avoid source names testset covers the counter and a source system that already uses ŷˍmor.

Measured effect

Three reductions of the same 24-state system in one session, reporting Julia's @timed compile-time counter for problem construction, the first residual evaluation, and the first field reconstruction:

construct (main) rhs (main) observed (main) construct (branch) rhs (branch) observed (branch)
ROM 1 4.176 s 0.588 s 0.163 s 4.213 s 1.385 s 0.162 s
ROM 2 0.936 s 0.083 s 0.041 s 0.012 s 0.0 s 0.0 s
ROM 3 0.130 s 0.082 s 0.041 s 0.0 s 0.0 s 0.0 s

On main the per-reduction cost never amortizes: ROM 3 still pays the same 0.082 s and 0.041 s as ROM 2. On this branch it goes to zero, because the second reduction reuses the first one's compiled functions. The first reduction is unchanged; it is doing the compilation that the later ones now reuse.

Verification

Julia 1.12.7, ModelingToolkit 11.41.0, MethodOfLines 1.3.0.

GROUP=Core julia +1 --project -e 'using Pkg; Pkg.test()'
Core/DataReduction.jl   |   15     15  15.9s
Core/array_structure.jl |   15     15  33.8s
Core/deim.jl            |   58     58  4m05.4s
Core/full_order.jl      |   32     32   4.3s
Core/interface.jl       |   30     30   0.4s
     Testing ModelOrderReduction tests passed
GROUP=QA julia +1 --project -e 'using Pkg; Pkg.test()'
QA/jet_tests.jl |    5      5  14.1s
QA/qa.jl        |   21     21  3m59.9s
     Testing ModelOrderReduction tests passed
GKSwstype=100 julia +1 --project=docs docs/make.jl
[ Info: Doctest: running doctests.
exit status 0 (full build with the executed FitzHugh-Nagumo tutorial, doctests, and link checks)

julia +1 --project=@runic -m Runic --check ., typos ., and git diff --check all exit 0. The QA and docs runs above were made against the identical tree before the final rebase onto the merged main; the Core run is post-rebase.

Not verified

  • Julia LTS/prerelease and the downgrade configuration were not run locally.
  • One Core run during development took 73 minutes rather than the usual 11. I traced that to precompilation contention in the shared depot with another job developing ModelingToolkit (Being precompiled by another process, and 233 dependencies loaded at different versions), not to this change: with warm caches every test file returns to its usual time, and deim itself is 0.01 s per call after the first. Worth knowing if CI ever looks slow for an unrelated reason.

Review notes

  • The generated names are now shared between reduced models in one session. That is the point, but it means two reduced models of different systems both call their state ŷˍmor. They are separate self-contained systems so nothing aliases across them, and the test suite exercises reduced models with POD dimensions 2, 3 and 4 in one session. Flagging it because it is the behavioral change a reviewer would most reasonably question.
  • GENERATED_SUFFIX is not exported and is not documented as public API; the tests reach into it so that they do not hard-code the spelling.

🤖 Generated with Claude Code

https://claude.ai/code/session_01H5RuLDtEazwTKPkNbPeZVu

gensym gave every reduced model fresh symbol names, so two reductions of
the same system produced different expressions and never shared generated
code. Build names from a fixed base plus an obscure suffix instead, and
append a counter when the source system already uses the name, which is
the case when reducing an already-reduced model.

Closes SciML#28.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Agent-Harness: Claude Code 2.1.263
Agent-Model: claude-opus-5
Agent-Session: https://claude.ai/code/session_01H5RuLDtEazwTKPkNbPeZVu
Claude-Session: https://claude.ai/code/session_01H5RuLDtEazwTKPkNbPeZVu
@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review September 7, 2026 05:41
@ChrisRackauckas
ChrisRackauckas merged commit 9f3b937 into SciML:main Sep 7, 2026
10 checks passed
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.

gensym recompilation

2 participants