Skip to content

Fix nested ForwardDiff tag mismatch in UJacobianWrapper for Rosenbrock solvers#1319

Open
AdityaPandeyCN wants to merge 3 commits intoSciML:masterfrom
AdityaPandeyCN:fix-nested-forwarddiff
Open

Fix nested ForwardDiff tag mismatch in UJacobianWrapper for Rosenbrock solvers#1319
AdityaPandeyCN wants to merge 3 commits intoSciML:masterfrom
AdityaPandeyCN:fix-nested-forwarddiff

Conversation

@AdityaPandeyCN
Copy link
Copy Markdown
Contributor

@AdityaPandeyCN AdityaPandeyCN commented Apr 12, 2026

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

Fix for SciML/OrdinaryDiffEq.jl#3381
When NonlinearSolve computes a Jacobian over an ODE solve,penters as Dual{NLTag} and Rosenbrock's internal ForwardDiff seeds u as Dual{OrdEqTag, Dual{NLTag}, CS}. UJacobianWrapper passes these mismatched types to the user function. p[1]*u[1] produces Dual{NLTag} outer due to tag precedence, but du expects Dual{OrdEqTag} outer, so the assignment crashes.
This promote p to match eltype(u) in UJacobianWrapper before calling f

Signed-off-by: AdityaPandeyCN <adityapand3y666@gmail.com>
…compat

Signed-off-by: AdityaPandeyCN <adityapand3y666@gmail.com>
DualU = eltype(u)
DualP = eltype(p)
if !(DualP <: DualU)
return DualU.(p)
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.

allocation per call

Copy link
Copy Markdown
Contributor Author

@AdityaPandeyCN AdityaPandeyCN Apr 12, 2026

Choose a reason for hiding this comment

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

I overlooked that you already have a PR for this(SciML/OrdinaryDiffEq.jl#3389). Should I close this?

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.

it's fine if you get to something good for it first 😅 it's just it should convert p once instead of each f call.

Signed-off-by: AdityaPandeyCN <adityapand3y666@gmail.com>
eltype(p) <: DualU && return p
cached = ff._promoted_p
cached isa AbstractArray{DualU} && return cached
ff._promoted_p = DualU.(p)
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.

still allocates

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This converts p once on the first f! call and caches it in _promoted_p all subsequent calls hit cached isa AbstractArray{DualU} && return cached.
Am I missing something?

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 the right place to do it. DiffEqBase solve has a promotion path, why not do it there?

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