`NonlinearFunction(::ODEFunction)` drops the vector argument of `jvp`/`vjp`, so `NonlinearProblem(::SteadyStateProblem)` throws for any ODE function with a `jvp`

Aperta
#1,663 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 3 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
78/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
julia

Direzione di ricerca

Read the conversion wrappers in src/scimlfunctions.jl, especially NonlinearFunction{iip}(f::ODEFunction) and ODEFunction{iip}(f::NonlinearFunction), then check test/convert_tests.jl for existing conversion coverage. Add tests for jvp and vjp in both directions and for in-place and out-of-place functions. Done means the converted products match the originals at t = Inf and the conversions succeed.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

When an ODEFunction is converted to a NonlinearFunction at t = Inf, the jvp and vjp wrappers copy the jac wrapper and lose the vector argument v. The resulting jvp has one argument too few, and the NonlinearFunction constructor rejects it. So NonlinearProblem(SteadyStateProblem(prob)) throws whenever prob.f has a jvp, both in place and out of place. The reverse conversion ODEFunction(::NonlinearFunction) has the same defect.

Versions

SciMLBase 3.58.0 (the latest registered release), Julia 1.12.6, Linux x86_64. The wrappers are unchanged on master (f75f097e, 2026-11-02, version 3.59.1). We read the source there but did not run it.

Reproducer
using SciMLBase

f!(du, u, p, t) = (du .= -u; nothing)
jvp!(Jv, v, u, p, t) = (Jv .= -v; nothing)            # documented in-place form
prob = SteadyStateProblem(ODEFunction{true}(f!; jvp = jvp!), [1.0, 2.0])

NonlinearProblem(prob)
# ERROR: Nonconforming functions detected. … Nonconforming functions: ["jvp"]

# out of place: jvp(v, u, p, t)
NonlinearFunction(ODEFunction{false}((u, p, t) -> -u; jvp = (v, u, p, t) -> -v))
# ERROR: All methods for the model function `f` had too few arguments. … Offending function: jvp
#   (::SciMLBase.var"#101#102")(u, p) @ scimlfunctions.jl:3409

# the reverse direction
ODEFunction(NonlinearFunction{true}((du, u, p) -> (du .= -u; nothing); jvp = (Jv, v, u, p) -> (Jv .= -v; nothing)))
# ERROR: Nonconforming functions detected. … Nonconforming functions: ["jvp"]

All three errors were reproduced on 3.58.0. NonlinearFunction(odef) called directly fails like the first case.

Actual vs expected

Actual: the conversions throw. If the arity check were skipped, the wrapper would call f.jvp(Jv, u, p, Inf), which is 4 arguments for a 5-argument function.

Expected: the conversion succeeds, and the converted jvp(Jv, v, u, p) equals f.jvp(Jv, v, u, p, Inf). Written by hand, this works:

nf = NonlinearFunction{true}((du, u, p) -> f!(du, u, p, Inf); jvp = (Jv, v, u, p) -> jvp!(Jv, v, u, p, Inf))
Jv = zeros(2); nf.jvp(Jv, [1.0, 1.0], [1.0, 2.0], nothing)   # Jv == [-1.0, -1.0]
Cause

src/scimlfunctions.jl (3.58.0; the same lines on master):

  • NonlinearFunction{iip}(f::ODEFunction), lines 3406-3417:

    _jvp = iip ? (Jv, u, p) -> (f.jvp(Jv, u, p, Inf); nothing) : (u, p) -> f.jvp(u, p, Inf)
    _vjp = iip ? (vJ, u, p) -> (f.vjp(vJ, u, p, Inf); nothing) : (u, p) -> f.vjp(u, p, Inf)
    
  • ODEFunction{iip}(f::NonlinearFunction), lines 3356-3365: (Jv, u, p, t) -> f.jvp(Jv, u, p) and (u, p, t) -> f.jvp(u, p), and the same for vjp.

  • The checks that reject them: isinplace(jvp, 4 + argshift, "jvp", iip) in NonlinearFunction{iip, specialize} (line 4777), and isinplace(jvp, 5, "jvp", iip) in ODEFunction{iip, specialize} (line 3191).

The wrappers date from 2022 (8e4bb3ae and #283). The jvp/vjp conversions have no test.

Suggested fix

Pass the vector through in all eight wrappers:

# NonlinearFunction{iip}(f::ODEFunction)
_jvp = iip ? (Jv, v, u, p) -> (f.jvp(Jv, v, u, p, Inf); nothing) : (v, u, p) -> f.jvp(v, u, p, Inf)
_vjp = iip ? (vJ, v, u, p) -> (f.vjp(vJ, v, u, p, Inf); nothing) : (v, u, p) -> f.vjp(v, u, p, Inf)

# ODEFunction{iip}(f::NonlinearFunction)
_jvp = iip ? (Jv, v, u, p, t) -> (f.jvp(Jv, v, u, p); nothing) : (v, u, p, t) -> f.jvp(v, u, p)
_vjp = iip ? (vJ, v, u, p, t) -> (f.vjp(vJ, v, u, p); nothing) : (v, u, p, t) -> f.vjp(v, u, p)

Suggested test: convert both ways, in place and out of place, with jvp and vjp set, and compare the products with the originals at t = Inf. It would fit in test/convert_tests.jl, which converts ODEProblems and SteadyStateProblems but has no conversion with a jvp or vjp set.

Related

We found no existing issue or PR. We searched SciMLBase, NonlinearSolve and SteadyStateDiffEq for "jvp" with "NonlinearFunction", "SteadyStateProblem", "Nonconforming" and "conversion". The nearest is #1430 (merged): it added the λ-shifted arity check (argshift) that these wrappers fail, but it did not touch the wrappers. We work around the bug with a NonlinearProblem method for our own problem type. We are glad to open a PR.

Lingua principale
Julia
Stelle
180
Fork
138
Merge medio
3g 18h
PR unite (30g)
5

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di SciML/SciMLBase.jl

Tutte le issue di SciML/SciMLBase.jl

Issue simili

Altre issue su Julia

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.