Skip to content

Zero array-element derivatives in NonlinearSystem conversion (facet A of #5066) - #5240

Draft
ChrisRackauckas-Claude wants to merge 4 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/5066-nonlinearsystem-array-deriv
Draft

ChrisRackauckas-Claude wants to merge 4 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/5066-nonlinearsystem-array-deriv

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Please ignore until reviewed by @ChrisRackauckas.

Summary

NonlinearSystem(sys) substitution rules were keyed only on D(x) for whole-array unknowns, so D(x[i]) survived when unknowns stayed unscalarized after hierarchical flattening, and complete then rejected the leftover Differential. This adds element-wise D(x[i]) => Symbolics.COMMON_ZERO rules (used after expand_array_derivatives! as well) and a regression test for issue #5066 facet A.

Review follow-up: @AayushSabharwal's suggestion applied — use Symbolics.COMMON_ZERO instead of 0.0, with the existing SU.is_array_shape guard on the element loop.

Part of #5066 (facet A only; facet B already fixed by #5163; facet C not addressed).

Fail before / pass after

On master NonlinearSystem (no element rules):

FAIL ON MASTER (expected):
Encountered operator `Differential(t, 1)` which has different independent variable than the one used in the system `nothing`.

Context:
Differential(t, 1)((x(t))[1])

With the fix (incl. COMMON_ZERO suggestion commit 48dfa3629d):

PASS ON FORK TIP (suggestion commit)

(steady-state solve: x[1]≈2/3, x[2]≈1/3, y≈2/3 from the issue's equations with D≡0)

Verification

cd lib/ModelingToolkitBase && GROUP=InterfaceII julia +1.12 --project=. -e 'using Pkg; Pkg.test()'

Tail (post-COMMON_ZERO validation run):

NonlinearSystem Test |  137     137  1m56.5s
...
Optimal Control + Constraints Tests |  31      2    33  18m18.7s
     Testing ModelingToolkitBase tests passed
EXIT:0

Also: Runic --check on touched files (exit 0); typos on touched files (clean).

Not verified

  • Facet C (abstract-typed parameter bindings graph) — out of scope for this PR.
  • Full All / other GROUP suites beyond InterfaceII.
  • Top-level ModelingToolkit package test suite (only ModelingToolkitBase InterfaceII).

What a reviewer should push back on

  • Whether element-wise rules should also cover observables the same way steady_state_initialization_eqs does (equations path currently only unknowns, matching prior behaviour).

Risk assessment

  • Risk: low — local change to NonlinearSystem substitution-rule construction.
  • Blast radius: steady-state conversion of systems with array unknowns / indexed derivatives.
  • Evidence: fail-before / pass-after on the issue reproducer; InterfaceII green including NonlinearSystem Test (137/137) with COMMON_ZERO.
  • Independent review: approved by @AayushSabharwal (suggestion applied on branch)
  • Merge: needs review

Please ignore this draft until reviewed by @ChrisRackauckas.

Harness: Cursor Agent CLI 2026.09.28-64d2043; model: auto; transcript: /log.txt

Risk assessment (independent review, Claude Code 2.1.301 claude-opus-5-5, reviewed head fba58bf)

  • Risk: low
  • Blast radius: ModelingToolkitBase.NonlinearSystem(sys::System) substitution rules only. Adds D(x[i]) => 0 rules for array-shaped unknowns (whole-array D(x) rule kept; its value changes from 0.0 to Symbolics.COMMON_ZERO). Affects steady-state conversion of systems whose unknowns are unscalarized arrays; scalar-unknown systems get identical rules apart from the zero constant. No public API change, no new deps.
  • Evidence: Reviewed head fba58bfda43a7ec1a1169ae9ffa3a2238d7eba34. Ran lib/ModelingToolkitBase/test/nonlinearsystem.jl (Julia 1.13, local env developing the checkout): PR source 137/137 pass; same test file with lib/ModelingToolkitBase/src from master (5abac29) 128 pass, 1 error in the new testset "NonlinearSystem conversion: array-element derivatives are zeroed" — fail-before / pass-after confirmed. Issue facet A reproducer: master throws Encountered operator `Differential(t, 1)` which has different independent variable; PR gives Success x=[0.6667, 0.3333] y=0.6667. Extra case with a slice derivative D(z[1:2]) ~ [...] plus D(z[3]) on a 3-vector: master errors the same way, PR solves to z=[2/3, 1/3, 1]. CI: 101 pass; the 6 failures are pre-existing — InterfaceI "Parsing Test" and RegressionI "Latexify recipes Test" error under Symbolics 7.45 (e.g. https://github.com/SciML/ModelingToolkit.jl/actions/runs/38850867728/job/116822205989), fixed on master by Update MTKBase tests and compat floors for Symbolics 7.43-7.45 #5281 (06b51a1) after this run; Documentation build and SciMLBase.jl/SymbolicIndexingInterface integration also fail on master (https://github.com/SciML/ModelingToolkit.jl/actions/runs/38856355754, https://github.com/SciML/ModelingToolkit.jl/actions/runs/38856355740). InterfaceII (which runs NonlinearSystem Test) green.
  • Independent review: Claude Code 2.1.301 claude-opus-5-5 rated it low, high confidence: small, local rule-set extension in one converter, verified fail-before/pass-after locally, CI reds are all pre-existing on master.
  • Merge: auto-merge candidate — after a merge of master so InterfaceI/RegressionI pick up Update MTKBase tests and compat floors for Symbolics 7.43-7.45 #5281 and go green.

🤖 Posted by an AI agent — harness: Claude Code 2.1.301 · model: claude-opus-5-5 (independent reviewer; appended by Claude Code 2.1.301 · claude-opus-5-5)
Conversation: https://claude.ai/code/session_01VZjwf7Ux9YtTzwHGHMqnsq

🤖 Automated comment from an AI agent running as @ChrisRackauckas — not written or reviewed by Chris.

Risk assessment (independent review, Codex gpt-6.1-sol, head fba58bf)

  • Verdict: CHANGES
  • Rating: Codex gpt-6.1-sol rated it low (L6) at head fba58bf
  • Risk: low (L6: repairs an error in the peripheral steady-state converter without changing its public signature; the regression discriminates, and a previously working scalar system produces equal symbolic equations). L2 also applies to the added assertions; no higher criterion was established.
  • Blast radius: ModelingToolkitBase.NonlinearSystem(sys::System) derivative substitution, including unscalarized array unknowns and expanded slices. This does not modify the general System constructor or mtkcompile implementation. No new public names, dependencies, copyleft licenses, skipped tests, loosened tolerances, or documented breaking changes; new-public-name documentation and a SemVer major bump are not applicable.
  • Evidence: Read the complete git diff origin/HEAD...HEAD, the linked issue, and the risk rubric. git diff --check origin/HEAD...HEAD passed; checkout status stayed clean. Local Julia was 1.12.4, with Symbolics 7.46.0 and NonlinearSolve 4.32.0 resolved identically for head and base. G1 pass: the new test's reference values follow independently from y=x[1]=2x[2], y+x[2]=1. G2 not applicable: no GPU kernels, AD rules, Reactant tracing, or MPI paths change; the CPU converter was exercised locally. G3 not applicable: the new dictionary is local; no shared state, cache, threading, or global default changes.
  • Merge: needs changes (findings 1–2). The low blast-radius rating does not waive the public-API restriction or the red checks.

Local commands used JULIA_DEPOT_PATH=<local path>, JULIA_NUM_THREADS=4, and scratch-local temporary files. In the commands below, S denotes <local path>. Tests ran sequentially against scratch package copies; the checkout was never edited.

  • timeout 3600 julia --startup-file=no --project="$S/env" "$S/run-target.jl" head: exit 0, Targeted NonlinearSystem | 137 137 9m22.9s. This includes the entire official lib/ModelingToolkitBase/test/nonlinearsystem.jl file.
  • timeout 3600 julia --startup-file=no --compiled-modules=existing --project="$S/base-env" "$S/run-target.jl" base: exit 1 against the full origin/HEAD package snapshot, commit 91fd79ea48; 128 passed, 1 errored. The sole error is the added testset at line 567: Encountered operator Differential(t, 1) which has different independent variable ... nothing, context Differential(t, 1)((x(t))[1]).
  • timeout 3600 julia --startup-file=no --compiled-modules=existing --project="$S/env" "$S/run-probes.jl": exit 0. Matrix solution [2 3; 3 4], slice solution [0.5, 0.5, 1.0], and scalar equations equal to those obtained with the original substitution rules. API output: Symbolics.COMMON_ZERO public=false; SymbolicUtils.zero_of_vartype public=true; the public zero constructor's result was asserted equal to COMMON_ZERO.
  • Unknown-size vector conversion was probed separately on both versions: head fails in the new index loop; base also fails, during equation substitution with an array-size mismatch. This experiment does not establish a regression and is not a finding.
  • Read-only gh pr checks, gh run view, and gh api .../actions/jobs/.../logs comparisons: four PR InterfaceI/RegressionI jobs fail, while the matching default-branch jobs pass at commit 06b51a13 after its test updates. PR docs and default-branch docs both fail because the OpenModelica link-check curl exits 28. PR and default-branch SciMLBase indexing jobs both error at comprehensive_indexing.jl:127 and :164, with the same one-element-vector BoundsError. The listed downgrade Optimization job is cancelled, not a demonstrated test failure. See the CI links below.

🤖 Posted by an AI agent — harness: Codex CLI 0.162.1 · model: gpt-6.1-sol
Conversation: local headless review run (no public session URL); transcript kept by the fleet master.

ChrisRackauckas and others added 2 commits October 1, 2026 10:44
Substitution rules keyed only on D(x) for whole-array unknowns left
D(x[i]) in residuals when unknowns stayed unscalarized after flattening.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.28-64d2043
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/orch-ibmtk/jobs/5066-cursor/log.txt on amdci2.julia.csail.mit.edu
Covers issue SciML#5066 facet A: unscalarized array unknowns with D(x[i]).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.28-64d2043
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/orch-ibmtk/jobs/5066-cursor/log.txt on amdci2.julia.csail.mit.edu
Comment thread lib/ModelingToolkitBase/src/systems/system.jl Outdated

This branch has not been deployed

No deployments
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.

3 participants