# Correct Way to Compose ReverseDiff and ForwardDiff

**URL:** <https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708>\
**Category:** Optimization (Mathematical)\
**Tags:** forwarddiff, reversediff, dual\
**Created:** [July 3, 2022, 4:35pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708 "2022-07-03T16:35:19Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![RS-Coop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rs-coop/32/32175_2.png) [@RS-Coop](https://discourse.julialang.org/u/RS-Coop)\
**Post date:** [July 3, 2022, 4:35pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/1 "2022-07-03T16:35:19Z")

</div>

I am trying to use ReverseDiff.jl and ForwardDiff.jl as a mixed mode AD approach to computing a Hessian vector product. I am using the following function:

```julia
import ForwardDiff as fdiff
import ReverseDiff as rdiff

function _hvp(f::F, x::S, v::S) where {F, S<:AbstractVector{<:AbstractFloat}}
	dual = fdiff.Dual.(x,v)

	return fdiff.partials.(rdiff.gradient(f, dual), 1)
end

```

but this is not giving me the expected output. See below for a simple example.

```julia
A = randn(2,2)

f(x) = x'*A*x

x = randn(2)
v = randn(2)

_hvp(f,x,v) ≈ (A+A')*v #returns false

```

What is the correct way to compose these two packages?

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [July 4, 2022, 2:54am UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/2 "2022-07-04T02:54:05Z")

</div>

Related thread:

> [@Mixed-mode automatic differentiation using ForwardDiff and ReverseDiff](https://discourse.julialang.org/t/mixed-mode-automatic-differentiation-using-forwarddiff-and-reversediff/74440):
>
> I need to take the gradient of a function. I can use ForwardDiff without any issues, but for part of my code I have found ReverseDiff to run much faster. The issue is that the other part of my code errors with ReverseDiff. The basic structure of my code looks something like function take\_my\_gradient(x) tmp = errors\_with\_reversediff(x) faster\_with\_reversediff(tmp) end Is it possible to differentiate my function using ForwardDiff on the part that doesn’t work with ReverseDiff and using…

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [July 4, 2022, 12:23pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/3 "2022-07-04T12:23:47Z")

</div>

The code you posted works for me (assuming `Dual`, `gradient`, and `partials` all come from ForwardDiff.jl):

```julia
julia> using ForwardDiff: Dual, gradient, partials

julia> function _hvp(f::F, x::S, v::S) where {F, S<:AbstractVector{<:AbstractFloat}}
           dual = Dual.(x, v)
           
           return partials.(gradient(f, dual), 1)
       end
_hvp (generic function with 1 method)

julia> A = randn(2, 2); x = randn(2); v = randn(2);

julia> f(x) = x' * A * x
f (generic function with 1 method)

julia> _hvp(f, x, v) ≈ (A + A') * v
true

```

It’s not clear from your post where the interplay between ForwardDiff.jl and ReverseDiff.jl comes in. Could you elaborate?

---

<div class="post-metadata">

**Author:** ![RS-Coop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rs-coop/32/32175_2.png) [@RS-Coop](https://discourse.julialang.org/u/RS-Coop)\
**Post date:** [July 4, 2022, 1:17pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/4 "2022-07-04T13:17:24Z")

</div>

Thanks, in my reading of this thread it only seems related in that both the ForwardDiff.jl and ReverseDiff.jl packages are being used, but there is nothing dealing with the composition of them. I think there is perhaps an ambiguity in the term “mixed mode”. In the referenced thread, the poster just wants to obtain the gradient by combining two different modes, whereas I want higher order derivatives using mixed-mode AD. If I am missing something feel free to point it out.

---

<div class="post-metadata">

**Author:** ![RS-Coop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rs-coop/32/32175_2.png) [@RS-Coop](https://discourse.julialang.org/u/RS-Coop)\
**Post date:** [July 4, 2022, 1:25pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/5 "2022-07-04T13:25:04Z")

</div>

Ah, yes, apologies for the ambiguity. I updated the question to clarify, but I want to use `ReverseDiff.gradient`. The goal is to have a forward-over-back approach, where ReverseDiff.jl is handling the backward mode. If I were to use `Zygote.gradient` instead, then the posted code would work.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [July 4, 2022, 2:06pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/6 "2022-07-04T14:06:38Z")

</div>

Looks like a bug in ReverseDiff, even for the first derivative of this `f`:

```julia
julia> ForwardDiff.gradient(f, x)
2-element Vector{Float64}:
 0.7876859520316463
 1.5891432962932512

julia> Zygote.gradient(f, x)
([0.7876859520316463, 1.589143296293251],)

julia> ReverseDiff.gradient(f, x) # wrong
2-element Vector{Float64}:
 1.1826512915394356
 1.154013797470248

julia> ReverseDiff.gradient(v -> v' * A' * v, x)
2-element Vector{Float64}:
 0.7876859520316463
 1.589143296293251

julia> ReverseDiff.gradient(x -> dot(x, A, x), x)
2-element Vector{Float64}:
 0.7876859520316463
 1.5891432962932512

julia> @which x'*A*x
*(tu::Union{Adjoint{T, var"#s967"}, Transpose{T, var"#s967"}} where {T, var"#s967"<:(AbstractVector)}, B::AbstractMatrix, v::AbstractVector)
     @ LinearAlgebra ~/.julia/dev/julia/usr/share/julia/stdlib/v1.9/LinearAlgebra/src/matmul.jl:1152

```

I see this on Julia 1.7 and later, but not on 1.6. Thus I presume it’s related to [PR 37898](https://github.com/JuliaLang/julia/pull/37898) for 3-arg `*`, but I don’t see why.

---

<div class="post-metadata">

**Author:** ![RS-Coop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rs-coop/32/32175_2.png) [@RS-Coop](https://discourse.julialang.org/u/RS-Coop)\
**Post date:** [July 4, 2022, 2:45pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/7 "2022-07-04T14:45:23Z")

</div>

I am on 1.6.4 and seeing that same issue.

---

<div class="post-metadata">

**Author:** ![RS-Coop](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rs-coop/32/32175_2.png) [@RS-Coop](https://discourse.julialang.org/u/RS-Coop)\
**Post date:** [July 4, 2022, 3:11pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/8 "2022-07-04T15:11:19Z")

</div>

There is [this](https://github.com/JuliaDiff/ReverseDiff.jl/issues/79) old issue on ReverseDiff.jl that may be related, I am uncertain.

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [July 4, 2022, 3:22pm UTC](https://discourse.julialang.org/t/correct-way-to-compose-reversediff-and-forwarddiff/83708/9 "2022-07-04T15:22:45Z")

</div>

I also see it on the official linux builds for v1.7.1. But I get the correct answers for `f2(x) = dot(x, A*x)` and `f3(x) = dot(x, A, x)`. Spooky.
