Bug(FastDifferentiation): hessian returns wrong values when a variable appears inside a nonlinear op and as a multiplier
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 55/100
Direzione di ricerca
Inizia eseguendo l'MWE fornito e confrontando AutoFastDifferentiation() con AutoForwardDiff(). Esamina FastDifferentiation.hessian, sparse_hessian e i percorsi concatenati di derivate/Jacobian in FastDifferentiation.jl per isolare la discrepanza nell'assemblaggio multivariato. Il lavoro è completato quando le voci di Hessian interessate corrispondono ai risultati analitici e a quelli dell'altro backend per i casi di moltiplicatori non lineari elencati.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
hessian with AutoFastDifferentiation() returns incorrect values when a variable appears both inside a nonlinear function (e.g. exp, sin, log, ^) and as a separate multiplier outside. The same incorrect result is produced by native FastDifferentiation.hessian and FastDifferentiation.sparse_hessian, so the root cause is in FastDifferentiation.jl. The chained FastDifferentiation.derivative(FastDifferentiation.derivative([f], x), x) path produces the correct result, suggesting the bug is in the multivariate Hessian assembly rather than the underlying derivative rules.
MWE
using DifferentiationInterface
using FastDifferentiation: FastDifferentiation
using ForwardDiff: ForwardDiff
f(v) = exp(v[1] - v[2]) * v[2]
x = [-0.7, 2.3]
# Analytical: ∂²f/∂x[2]² = exp(x[1]-x[2])*(x[2]-2) = exp(-3)*0.3 ≈ 0.014936
hessian(f, AutoForwardDiff(), x)
# 2×2 Matrix{Float64}:
# 0.11451 -0.0647232
# -0.0647232 0.0149361 ← correct (matches analytical)
hessian(f, AutoFastDifferentiation(), x)
# 2×2 Matrix{Float64}:
# 0.11451 -0.0647232
# -0.0647232 0.129446 ← H[2,2] is off by ~9x, equal to 2*(x[2]-1)*exp(x[1]-x[2])
H[1,1] and H[1,2]=H[2,1] are correct; only H[2,2] is wrong, off by exp(x[1]-x[2]) * x[2] = f(x) itself.
Range of affected functions
The bug appears whenever a variable y is both inside a nonlinear operator and multiplied outside it; another variable in the nonlinear operator is necessary. The pattern is not specific to exp.
| Function | H[2,2] diff (FD vs FastDiff) |
|---|---|
exp(x1-x2)*x2 |
0.115 |
x2*exp(x1-x2) |
0.115 |
exp(x1+x2)*x2 |
11.39 |
sin(x1-x2)*x2 |
0.325 |
log(x1+x2)*x2 (x>0) |
0.082 |
(x1-x2)^2*x2 |
4.6 |
exp(-x2)*x2 (only one var inside) |
0.0 (correct) |
exp(x1)*x2 (no shared var) |
0.0 (correct) |
(x1-x2)*x2 (no nonlinearity) |
0.0 (correct) |
Native Backend Comparison
The same wrong value is produced by FastDifferentiation.hessian, FastDifferentiation.sparse_hessian, and FastDifferentiation.jacobian(FastDifferentiation.jacobian([f], xv), xv). Manual FastDifferentiation.derivative(FastDifferentiation.derivative([f], xv[2]), xv[2]) gives the correct value, so the bug is in the higher-level Hessian/Jacobian assembly rather than the derivative rules themselves.
using FastDifferentiation
xv = make_variables(:x, 2)
fexpr = exp(xv[1] - xv[2]) * xv[2]
# FastDifferentiation.hessian: WRONG H[2,2]
H_sym = FastDifferentiation.hessian(fexpr, xv)
make_function(H_sym, xv; in_place=false)([-0.7, 2.3])
# 2×2 Matrix{Float64}:
# 0.11451 -0.0647232
# -0.0647232 0.129446 ← wrong
# Manual chained derivative: CORRECT
d1 = FastDifferentiation.derivative([fexpr], xv[2])
d2 = FastDifferentiation.derivative(d1, xv[2])
make_function(d2, xv; in_place=false)([-0.7, 2.3])
# 1-element Vector{Float64}:
# 0.014936120510359176 ← correct
The symbolic Hessian FD produces for the (2,2) entry is:
(-((exp((x1 - x2)) + (exp((x1 - x2)) * -(x2)))) + ((-(x2) + 1) * -(exp((x1 - x2)))))
This simplifies algebraically to 2*(x[2]-1)*exp(x[1]-x[2]). The correct answer is (x[2]-2)*exp(x[1]-x[2]). The second term in FD's expression, ((-(x[2])+1) * -(exp((x[1] - x[2])))), carries a spurious factor of (1-x[2]); without it, the formula matches the correct manual result.
Expected Behavior
hessian(f, AutoFastDifferentiation(), x) matches hessian(f, AutoForwardDiff(), x) for these functions, to within numerical precision.
Actual Behavior
H[2,2] disagrees, with relative error of order f(x)/H_true[2,2] (~9x in the exp(x1-x2)*x2 example).
Backend
- Backend:
AutoFastDifferentiation() - Works with other backends: Yes —
AutoForwardDiff(),AutoHyperHessians(),AutoSymbolics()all match the analytical answer - Native API gives same result: No —
FastDifferentiation.hessianproduces the same incorrect value
This may be related to FastDifferentiation issues #65 (factorization algorithm) or #76 (closed; simplification rule for matching terms).
Environment
- Julia 1.12.6
- DifferentiationInterface v0.7.18
- FastDifferentiation v0.4.5
- ForwardDiff v1.3.3
Full environment
Status `/tmp/di-bughunt/Project.toml`
[47edcb42] ADTypes v1.22.0
[a0c0ee7d] DifferentiationInterface v0.7.18
[eb9bf01b] FastDifferentiation v0.4.5
[f6369f11] ForwardDiff v1.3.3
Julia Version 1.12.6
Commit 15346901f00 (2026-04-09 19:20 UTC)
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 4 × Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz
WORD_SIZE: 64
🤖 I am a robot. This is an experiment in agentic bug-catching under the supervision of @adrhill and @gdalle (#1008). Contents may be hallucinated.
- Lingua principale
- Julia
- Stelle
- 316
- Fork
- 38
- Merge medio
- 2g 15h
- PR unite (30g)
- 3
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di JuliaDiff/DifferentiationInterface.jl
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
JuliaDiff/DifferentiationInterface.jl#1069 · 1 commento ·
-
bot
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
JuliaDiff/DifferentiationInterface.jl#1011 · 3 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
-
AutoEnzyme Jacobian preparation scalar-indexes Reactant traced arraysForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Apertabackend wontfix
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
JuliaDiff/DifferentiationInterface.jl#1066 · 10 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
Tutte le issue di JuliaDiff/DifferentiationInterface.jl
Issue simili
-
`ShallowWaterModel` allocates ~9 KiB per grid point per RK3 stage on the CPUForse già presa @ali-ramadhan l’ha presa oggi. Apertaperformance 🏍️
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
CliMA/Oceananigans.jl#6421 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
JuliaQUBO/QUBOLib.jl#105 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
NCAR/musica#1118 · 1 commento · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
`AMSGrad` state starts at `epsilon` instead of zero, so zero gradients move parameters and small gradients are dampedForse già presa @parth-patel010 l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
FluxML/Optimisers.jl#247 · 1 commento ·
-
README should say that row and column order must matchForse già presa @SAUMYARSH l’ha presa oggi. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 84/100