Skip to content

Share ordinary solver paths with Reactant - #4436

Draft
ChrisRackauckas-Claude wants to merge 30 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/reactant-jit-solve
Draft

ChrisRackauckas-Claude wants to merge 30 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/reactant-jit-solve

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Aug 30, 2026 •

Copy link
Copy Markdown
Member

Please ignore until reviewed by @ChrisRackauckas.

What changed and why

Explicit ODE solves inside Reactant use the ordinary solver loop, step acceptance/rejection, FSAL updates, initial-step estimator, and I/PI/PID controllers on a shared path (no separate Reactant solver). This tip addresses Chris's 2026-09-27 review comments that are in-scope for this PR, plus Round-6/7 host-parity fixes:

  1. DiffEqBase.has_callbacks is public (00b2ab09d, docs placement 399ec3b92).
  2. Reactant test deps are self-contained (1648dcd8a): group bootstraps released Reactant 0.2.289 / ReactantCore 0.1.23.
  3. Merged origin/master (033d5949c) keeping master's Float32: initdt falls back to dt=1e-6 via absolute eps guard, +27% steps on Lorenz #4601 tiny-dt fallback and this PR's Reactant @trace/NaN path (4bf5da8cd); unitful eps unwrap in bb9ec861e.
  4. Round-6 initdt host parity (9801a0ddb): restore IIP :dt_epsilon message; drop OOP tiny-dt fallback (master's Float32: initdt falls back to dt=1e-6 via absolute eps guard, +27% steps on Lorenz #4601 is IIP-only).
  5. Round-7: remove SDIRK mass-matrix work from this PR (c364243b6): restore OrdinaryDiffEqSDIRK and the Differentiation ScalarOperator mass-matrix test to match origin/master exactly. ESDIRK λI / ScalarOperator support is a separate follow-up.

Follow-ups (separate PRs):

Part of #4436.

Round-7 review (CHANGES → fixed in c364243b6)

  1. Removed _mmdiag_values, the isconstant guard, and the UniformScaling import from SDIRK. git diff origin/master -- lib/OrdinaryDiffEqSDIRK is empty. Reactant does not need that path.
  2. Restored master's Differentiation test unchanged, including sol_t.u[end][1] ≈ 0.5 atol = 1e-5. Differentiation Core fails on this tip the same way as on master (diag(::ScalarOperator) MethodError from only allow diagonal M for ESDIRK #4560).

Verification (tip c364243b6)

# Paths identical to master
git diff origin/master -- lib/OrdinaryDiffEqSDIRK lib/OrdinaryDiffEqDifferentiation/test
# (empty)

# Runic + typos
runic --check … exit 0
typos … exit 0

# OrdinaryDiffEqSDIRK
GROUP=Core → SDIRK_CORE_EXIT=0
GROUP=QA   → SDIRK_QA_EXIT=0
# Direct qa.jl ExplicitImports: all_qualified_accesses_{are_public,via_owners} PASS
# (Round-7 SciMLOperators finding gone)

# OrdinaryDiffEqDifferentiation GROUP=Core
# PR and master both:
#   ScalarOperator mass matrix | 5 Pass, 1 Error, 6 Total
#   MethodError: no method matching diag(::ScalarOperator…)

# GROUP=InterfaceI → IFACE_EXIT=0
# GROUP=Reactant   → Reactant Tests 208/208, REACTANT_EXIT=0

CI triage

Differentiation Core is pre-existing on master from #4560 (diag(mass_matrix) in ESDIRK). The test is the correct #3916 physics assertion; it is not edited or skipped here. Tracked in #4661/#4582.

Other reds previously listed on bb9ec861e (SciMLSensitivity Core1, downgrade DiffEqBase, DelayDiffEq Waltman Inf/NaN on master+PR, DiffEqBase lts, GPU, NonlinearSolve Core, Rosenbrock QA / open #4668) remain master-caused.

Risk assessment

  • Risk: low. Round-7 only deletes out-of-scope SDIRK/test edits; initdt Reactant path unchanged since 9801a0ddb.
  • Blast radius: restores master ESDIRK ScalarOperator behaviour (loud MethodError). No new host semantics.
  • Evidence: SDIRK Core/QA green; Diff Core fails identically to master; InterfaceI + Reactant green; SDIRK/Diff test paths bit-identical to origin/master.
  • Independent review: pending.
  • Merge: needs human review.

What was NOT verified

Please ignore this draft until reviewed by @ChrisRackauckas.

Cursor Agent CLI, model auto. Transcript under /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/ on amdci2.julia.csail.mit.edu.

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

Implementation/CI plan:

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.151.0
Agent-Model: unknown
Agent-Session: local session ID 01a04f92-0d12-7990-926c-f3e5a23f3a31
Comment thread lib/OrdinaryDiffEqCore/src/solve.jl Outdated
Comment on lines +1001 to +1004
if ReactantCore.within_compile()
isnothing(dt) && integrator.opts.adaptive && auto_dt_reset!(integrator)
return nothing
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't doing the tdir flip? Why not do this the other way around and just if not in a compile, do the error messages?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 5ad0c97: handle_dt!(integrator, dt) always runs auto_dt_reset! (when needed) and the tdir sign fix via abs(dt) * tdir on the shared path. Only the host diagnostics (sign/isnan error messages) are gated behind !ReactantCore.within_compile(), because those predicates cannot drive ordinary if on traced values. Adaptive Reactant suite is 208/208 after this change (previously failed on TracedRNumber{Bool} in the old dt > 0 branch).

Comment thread lib/OrdinaryDiffEqCore/src/solve.jl Outdated
Comment on lines +932 to +936
if ReactantCore.within_compile()
return integrator.opts.adaptive ?
_traced_adaptive_solve!(integrator, integrator.controller_cache) :
_traced_fixed_step_solve!(integrator)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this treated as separate code instead of integrating it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — the separate _traced_adaptive_solve! / _traced_fixed_step_solve! entry points are gone. SciMLBase.solve! is now one shared loop: ReactantCore.@trace while around _solve_step!, with compile-only finalization (_traced_finalize_solution) after the traced loop. Host-only pieces (error checks, handle_tstop!, postamble) stay behind within_compile() gates rather than a second solver.

throw(ArgumentError("implicit algorithms are not supported inside Reactant compilation"))
!adaptive && isnothing(dt) &&
throw(ArgumentError("dt is required for fixed-step solves inside Reactant compilation"))
isempty(saveat) || throw(ArgumentError("saveat is not supported inside Reactant compilation"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't reactant want a constant size output? That would require using saveat

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — a constant-size compiled output would naturally be driven by saveat (or a fixed save_everystep count). Under compile today we force save_everystep=false / save_end=true so the traced solution is a single endpoint, which is statically sized without needing a dynamic save queue. Supporting saveat is the right next step once we can materialize a fixed-length traced timeseries from a compile-time-known grid; leaving the throw until that lands rather than half-supporting a growing BinaryHeap.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we really need saveat for reactant

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracked in #4657 together with the other options still rejected under compilation (save_everystep, tstops, callbacks, implicit algorithms, etc.). This PR keeps the explicit ArgumentError for saveat inside Reactant compilation.

Cursor Agent CLI 2026.09.26-dd393fe, model auto.

Comment on lines +207 to +208
!adaptive && isnothing(dt) &&
throw(ArgumentError("dt is required for fixed-step solves inside Reactant compilation"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this different? dt with tstops is the only other way, but tstops aren't supported, so this is an unnecessary check?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept on purpose: under compile, fixed-step still needs a concrete dt because auto-dt only runs for adaptive algorithms, and tstops/d_discontinuities are also rejected in the same gate. Without dt, a non-adaptive compiled solve has no step size to advance. Happy to drop the check once fixed-step can take a compile-time-constant alternative (e.g. a static tstop grid), but today it is not redundant with the tstops rejection.

Comment on lines +205 to +206
isimplicit(alg) &&
throw(ArgumentError("implicit algorithms are not supported inside Reactant compilation"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implicit algorithms still need nonlinear solves / W-factorization paths that are not yet exercised on the shared traced step. The gate fails fast at _ode_init rather than tracing into unsupported caches. Explicit adaptive/fixed-step (Tsit5 etc.) is what the Reactant suite covers; lifting this is follow-up once OrdinaryDiffEqNonlinearSolve / W construction is Reactant-safe end-to-end.

ChrisRackauckas and others added 2 commits September 5, 2026 09:17
Route compiled solves through the ordinary step loop, initial-step estimator,
FSAL update, and I/PI controllers. Promote loop-carried state for tracing and
retain narrow adapters for static output and endpoint handling.

Cover custom controllers, zero dynamics, in-place fixed steps, and rejected
first steps. Merge current master to resolve the test-group configuration and
retain upstream fixes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.153.4
Agent-Model: gpt-6-astra
Agent-Session: local transcript /home/crackauc/.codex/sessions/2026/09/05/rollout-2026-09-05T07-40-10-01a0715e-73c9-7e21-a18b-c5b0504a4bf3.jsonl
Keep the ordinary integrator's active FSAL aliases and select cache buffers at
the tracing boundary. Composite cache initialization buffers need not belong to
the active solver.

The existing composite tests fail 2 of 16 checks without this correction and
pass all 16 with it. Reactant passes 178/178 and QA passes 109/109.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.153.4
Agent-Model: gpt-6-astra
Agent-Session: local transcript /home/crackauc/.codex/sessions/2026/09/05/rollout-2026-09-05T07-40-10-01a0715e-73c9-7e21-a18b-c5b0504a4bf3.jsonl
@ChrisRackauckas-Claude ChrisRackauckas-Claude changed the title Trace explicit ODE solves under Reactant Share ordinary solver paths with Reactant Sep 5, 2026
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member Author

Reworked the implementation to use the ordinary solver loop, initial-step estimator, controllers, acceptance/rejection, and FSAL update. Removed the separate traced solver and initial-step implementations. The remaining compilation checks handle traced state, buffer aliases, endpoint stops, and output/error boundaries.

Local verification: Reactant 178/178; QA 109/109; full InterfaceI passed in 2367.4 seconds; targeted composite tests 16/16; docs build, Runic, and typos passed. The new IController regression errors on the original implementation and passes with this revision; the updated body includes the code and output.

Commits:

The PR remains a draft and should be ignored until reviewed by @ChrisRackauckas. CI is running.

🤖 Generated with Codex CLI 0.153.4 (model: gpt-6-astra). Session: local transcript /home/crackauc/.codex/sessions/2026/09/05/rollout-2026-09-05T07-40-10-01a0715e-73c9-7e21-a18b-c5b0504a4bf3.jsonl.

if isinplace(integrator.sol.prob)
recursivecopy!(integrator.fsalfirst, integrator.fsallast)
fsalfirst, fsallast = if ReactantCore.within_compile()
get_fsalfirstlast(integrator.cache, integrator.u)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would this be a function call only within compile?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both execution modes now use the same FSAL-buffer accessor and copy. Composite/default/constant caches retain their active integrator buffers because their initialization accessor does not identify the current runtime buffers.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

Comment on lines +282 to +288
if ReactantCore.within_compile()
dt = integrator.opts.adaptive ? integrator.dt : integrator.dtcache
integrator.dt = integrator.tdir * min(
abs(dt), abs(first_tstop(integrator) - integrator.tdir * integrator.t)
)
return nothing
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is clamping ignored in reactant compile?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the compilation-only timestep-clipping implementation. Both modes now use the normal stop flags, clipping, roundoff tolerance, and restoration of the proposed timestep.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

integrator.accept_step = (
!integrator.isout &&
!integrator.isout &
accept_step_controller(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function modifies?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The built-in acceptance predicates only inspect controller state, but eager evaluation was unnecessary. The shared path now evaluates the predicate only when the candidate is in-domain, preserving short-circuit behavior for custom controllers as well.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

Comment thread lib/OrdinaryDiffEqCore/src/initdt.jl Outdated
# because it also checks if partials are NaN
# https://discourse.julialang.org/t/incorporating-forcing-functions-in-the-ode-model/70133/26
if isnan(d₁)
if !ReactantCore.within_compile() && isnan(d₁)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would reactant compile not do a NaN check?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NaN checks and fallback are now part of the common initial-step control flow, including compiled solves. Added native/compiled fallback parity tests for both RHS forms. The IIP path also checks the derivative directly because the fast-math norm can hide NaNs from a later scalar check; Float32/Float64 native regressions cover that fallback.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

Comment thread lib/OrdinaryDiffEqCore/src/initdt.jl Outdated
end
return tdir * max(dtmin, min(100dt₀, dt₁, dtmax_tdir))
result_dt = tdir * max(dtmin, min(100dt₀, dt₁, dtmax_tdir))
if ReactantCore.within_compile()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is this doing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That deferred correction was compensating for skipped early decisions during tracing. Removed it: NaN and constant-derivative decisions now occur in the shared initial-step path.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

Comment thread lib/OrdinaryDiffEqCore/src/reactant.jl Outdated
Comment on lines +3 to +5
# Function wrappers hide types from Reactant and provide no compile-time reuse inside `@jit`.
SciMLBase.specialization(::ODEFunction{iip, SciMLBase.AutoSpecialize}) where {iip} =
ReactantCore.within_compile() ? SciMLBase.FullSpecialize : SciMLBase.AutoSpecialize

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is piracy, should go to SciMLBase

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved specialization dispatch to a ReactantCore extension owned by SciMLBase, with instance/type and outside-compilation tests: SciML/SciMLBase.jl#1564. OrdinaryDiffEq no longer defines those methods.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

Comment thread lib/OrdinaryDiffEqCore/src/solve.jl Outdated
Comment on lines +789 to +791
if ReactantCore.within_compile() && adaptive &&
!(controller_cache isa Union{IControllerCache, PIControllerCache})
throw(ArgumentError("only IController and PIController are supported inside Reactant compilation"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the I/PI whitelist. PID now uses the common controller implementation with a traceable error history, and is covered by the compiled solve tests.

Updated in abb04b3. Clean local Reactant suite: 208/208; QA: 109/109.

ChrisRackauckas and others added 8 commits September 12, 2026 06:49
Use shared FSAL access, stop clipping, controller acceptance, and initial-step
control flow. Support PID tuple history and keep specialization in SciMLBase.
Cover compiled clipping, PID and NaN parity plus native controller reinit
and NaN initial-step regressions. Merge current upstream solver changes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.153.4
Agent-Model: gpt-6-astra
Agent-Session: local transcript /home/crackauc/.codex/sessions/2026/09/05/rollout-2026-09-05T07-40-10-01a0715e-73c9-7e21-a18b-c5b0504a4bf3.jsonl
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Codex <noreply@openai.com>
Agent-Harness: Codex CLI 0.153.4
Agent-Model: gpt-6-astra
Agent-Session: local transcript /home/crackauc/.codex/sessions/2026/09/05/rollout-2026-09-05T07-40-10-01a0715e-73c9-7e21-a18b-c5b0504a4bf3.jsonl
Resolve the Project.toml test-target conflict by keeping master's
FunctionWrappersWrappers entry and this branch's Reactant extras. Raise
the SciMLBase floor to 3.56 for the released parametric-retcode work,
drop the SciMLBase PR branch pin, point the Reactant test group at
EnzymeAD/Reactant.jl main, and keep handle_dt!/stats paths
Reactant-compatible after the merge.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Traced enums landed on Reactant main but are not released yet
(latest registry is still v0.2.288). Resolve Reactant/ReactantCore
from main so the Reactant group exercises the merged enum design.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Avoid traced `dt > 0` / `iszero(dt)` as ordinary `if` conditions during
compilation. Keep auto_dt_reset! and the tdir sign correction on the
shared path; restrict host-only error/NaN diagnostics to non-compile
runs, matching the review request on the compile early-return.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Move the initial-dt epsilon warning into the non-NaN branch so JET no
longer sees an undefined dt₀ after ReactantCore.@trace if, and teach
InterfaceIII/StochasticDiffEq CustomArray tests DiffEqBase.NAN_CHECK.
Drop root Project.toml Reactant main sources (GROUP=Reactant still pins
via runtests.jl) so Downgrade does not resolve Reactant from git.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Bring in Trapezoid non-diagonal mass-matrix support (SciML#4631), BDF JET
FullSpecialize (SciML#4627), and other master fixes needed for Sublibrary CI.
…acks

update_fsal! was routing through get_fsalfirstlast, which returns throwaway
zero(...) for RKM/ExpRK and wiped inplace FSAL (order ~0). Restore
integrator.fsalfirst/fsallast copies. Match DelayDiffEq's tstop_tol via
eps(magnitude). Handle ScalarOperator in _mmdiag. Treat empty CallbackSet
as no callbacks for GlobalErrorEstimation (DiffEqBase Julia≥1.12 erasure).

Co-authored-by: Cursor <cursoragent@cursor.com>
ChrisRackauckas and others added 11 commits September 26, 2026 15:57
Prefer stable cache-owned FSAL buffers after Reactant dealiasing while
keeping throwaway get_fsalfirstlast fallbacks for ExpRK; specialize
_mmdiag for UniformScaling; path-source SDIRK for NonlinearSolve tests;
and avoid non-public DiffEqBase.has_callbacks in GlobalDiffEq QA.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use NAN_CHECK only when a method exists so master's CustomArray fixture
works again; select FSAL via integrator buffers on the host (cache fields
only under Reactant when owned by the cache); bootstrap Reactant at the
group boundary for GROUP=Everything; add an ExpRK FSAL allocation guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
Pkg.test runs with --check-bounds=yes, under which ETDRK2 step! allocates a
constant ~64 bytes on master and head alike, so the absolute step! == 0
assertion failed in CI on both revisions. Guard size-independence instead
(step! allocations at n=10 equal those at n=10000) and keep the
update_fsal! == 0 assertions, which discriminate: they fail on 080d4c1
with 576/320384 bytes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
Some caches return an owned first buffer and a fresh last one via
get_fsalfirstlast; accepting the pair when either buffer is owned could
bind perform_step! to a throwaway. Require both to be cache-owned and
keep host behavior unchanged.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
The broader sibling [sources] block made the downgrade job resolve local
Core/BDF/FIRK/Rosenbrock/Differentiation/DevTools/DiffEqBase (PR head code)
against downgraded registry deps, and nsa_stats_tests.jl:91 failed under
Julia 1.11 (1.28235 <= 1.26195). Master's NonlinearSolve Project.toml has no
[sources] and that downgrade stays green. Path-source only SDIRK, which the
Trapezoid DAE tests need for in-tree SciML#4631 before that release is in
General; nsa_stats passes 39/39 locally with this package selection.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
NAN_CHECK on Vector{<:Dual} only sees NaN values, not NaN Dual partials;
that is DiffEqBase's behavior, not something this code relies on.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
Master's NonlinearSolve Project.toml has no [sources] block; the block added
in 080d4c1 makes the downgrade job resolve local siblings against
downgraded deps and fails nsa_stats_tests.jl:91 under Julia 1.11, and
narrowing it to SDIRK makes the downgrade job unresolvable (local SDIRK
2.9.7 vs downgrade-pinned BDF 2.0.0). With no [sources] the downgrade job
resolves registry packages as on master. The regular NonlinearSolve Core
job then uses registry SDIRK 2.9.6, which lacks SciML#4631; the Trapezoid
mass-matrix and nsa_noinit failures that produces are master-latent (see
CI triage in the PR body).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
Release versioning is a maintainer call; this PR does not bump versions.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: opencode <noreply@opencode.ai>
Agent-Harness: opencode 1.18.31
Agent-Model: opencode/longcat-2.5-preview-free
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-opencode/log.txt on amdci2.julia.csail.mit.edu
Comment thread lib/GlobalDiffEq/src/companion.jl Outdated
Comment on lines +10 to +12
# DiffEqBase.has_callbacks is not public (ExplicitImports QA). Mirror its
# semantics with the public `isempty(::CallbackSet)` API so empty erasure
# CallbackSets injected on Julia ≥1.12 are not treated as real callbacks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just make it public

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 00b2ab0 (docs placement fix in 399ec3b): DiffEqBase.has_callbacks is now public, documented next to merge_problem_kwargs on the DiffEqBase developer API page, covered by an ispublic + empty-CallbackSet unit test, and GlobalDiffEq calls DiffEqBase.has_callbacks directly (the local _has_nonzero_callbacks workaround is gone).

Cursor Agent CLI 2026.09.26-dd393fe, model auto.

Comment thread Project.toml Outdated
Comment on lines +128 to +129
Reactant = "3c362404-f566-11ee-1572-e11a4b42c853"
ReactantCore = "a3311ec8-5e00-46d5-b541-4f83e724a433"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if reactant is a separate test group, is this needed here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 1648dcd: Reactant/ReactantCore are no longer in the root [extras]/[targets]/[compat]. The Reactant group bootstraps itself in reactant_group() with the released packages that include traced enums (Reactant 0.2.289 and ReactantCore 0.1.23), replacing the previous pin to EnzymeAD/Reactant.jl main.

Cursor Agent CLI 2026.09.26-dd393fe, model auto.

ChrisRackauckas and others added 2 commits September 27, 2026 10:31
Document the helper on the DiffEqBase API pages and drop the local
_has_nonzero_callbacks workaround that mirrored its empty-CallbackSet
semantics for ExplicitImports QA.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Drop Reactant/ReactantCore from the root extras/targets/compat now that
the Reactant group bootstraps the released packages with traced enums.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
ChrisRackauckas and others added 6 commits September 27, 2026 12:30
Avoid a Documenter duplicate with the user-facing DiffEqBase page; the
helper lives next to merge_problem_kwargs in the developer extension API.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Resolve initdt conflicts by keeping Reactant-traced NaN/control flow while
adopting master's SciML#4601 tiny-first-guess fallback (refine before falling
back). Keep both the Reactant NaN and Float32/Float64 initdt regression tests.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.09.26-dd393fe
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Merge of master's always-refine + tiny fallback into the Reactant @trace
path: use bitwise tiny_first, refine always, then ifelse for the fallback
so nested @trace/SSA issues do not break IIP adaptive compiles.

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/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
The Reactant-safe `&`/`|` tiny-dt fallback always evaluates
`eps(::Type)`, which MethodErrors on DynamicQuantities.Quantity and
broke Downstream. Unwrap via SciMLBase.value like dtmin.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI
Agent-Model: auto
Re-emit master's :dt_epsilon message on the IIP path, drop the OOP
tiny-dt fallback (SciML#4601 is IIP-only), and reject non-constant
ScalarOperator mass matrices in ESDIRK instead of returning a wrong
constant answer.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu
Restore OrdinaryDiffEqSDIRK and the Differentiation ScalarOperator
mass-matrix test to match master. ESDIRK λI/ScalarOperator support
belongs in a separate follow-up, not this Reactant PR.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/OrdinaryDiffEq.jl/jobs/4436-cursor/log.txt on amdci2.julia.csail.mit.edu

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.

2 participants