# \`ForwardDiff\` and \`LAPACK\` don't get along

**URL:** https://discourse.julialang.org/t/forwarddiff-and-lapack-dont-get-along/58397
**Category:** Optimization (Mathematical)
**Tags:** optim, vscode, forwarddiff
**Created:** [April 1, 2021, 9:42pm UTC](https://discourse.julialang.org/t/forwarddiff-and-lapack-dont-get-along/58397 "2021-04-01T21:42:44Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![Ross\_Boylan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ross_boylan/32/9210_2.png) [@Ross\_Boylan](https://discourse.julialang.org/u/Ross_Boylan)
#### Post date: [April 1, 2021, 9:42pm UTC](https://discourse.julialang.org/t/forwarddiff-and-lapack-dont-get-along/58397/1 "2021-04-01T21:42:44Z")

</div>

`ForwardDiff` only works with pure julia code AFAIK, which means it won’t work with the external calls to `BLAS` or `LAPACK`. When I inadvertently combine them by using `qr()` it doesn’t work. The question is what to do about it.

Here’s an illustration of the problem:

```julia
using Optim
using LinearAlgebra

function bam(n=5)
    T = hcat(ones(n), 1:n)
    QR = qr(T)
    "not a sensible optimization target, but enough to show the problem"
    function target(β)
        sum(QR.Q * β)
    end
    r = optimize(target, zeros(n), Newton(); autodiff=:forward)
end

bam()

ERROR: LoadError: MethodError: no method matching lmul!(::LinearAlgebra.QRCompactWYQ{ForwardDiff.Dual{ForwardDiff.Tag{var"#target#5"{LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}}}, Float64}, Float64, 5}, Matrix{ForwardDiff.Dual{ForwardDiff.Tag{var"#target#5"{LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}}}, Float64}, Float64, 5}}}, ::Vector{ForwardDiff.Dual{ForwardDiff.Tag{var"#target#5"{LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}}}, Float64}, Float64, 5}})

```

The expression `QR.Q * β` is the call that triggers the error.

As a bonus, when I try to debug this in VS Code it seems to crash the language server reliably.

The code for qr includes

```julia
lmul!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} =
    LAPACK.gemqrt!('L','N',A.factors,A.T,B)

```

Since it is certainly not true that `ForwardDiff.Dual <: BlasFloat`, the failure to find a matching declaration is unsurprising.

One solution would be to revert to my previous, less “optimized” code, which instantiated the entire `Q` matrix first and thus apparently never called the external linear algebra libraries (which seems a little odd).

Computing derivatives analytically is not at all appealing for the real problem.

---

<div class="post-metadata">

### Author: ![Ross\_Boylan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ross_boylan/32/9210_2.png) [@Ross\_Boylan](https://discourse.julialang.org/u/Ross_Boylan)
#### Post date: [April 1, 2021, 11:04pm UTC](https://discourse.julialang.org/t/forwarddiff-and-lapack-dont-get-along/58397/2 "2021-04-01T23:04:46Z")

</div>

Another solution: use `QR = qr(T, Val(true))` which avoids the call to LAPACK. Since my fake target function is unbounded, the optimization bails out, but `Optim` and `qr` are working together OK.

The rules for qr also state that if the element type of the argument is not a BLAS type it will construct a different type of object, which might also work. There’s probably some way to convert them to `ForwardDiff.Dual`.

Probably something similar explains the fact that my previous matrix multiplication code was not using external libraries: the types involved were not BLAS types, but there was a fallback implementation in pure julia.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [April 2, 2021, 2:23pm UTC](https://discourse.julialang.org/t/forwarddiff-and-lapack-dont-get-along/58397/3 "2021-04-02T14:23:59Z")

</div>

> [@Ross\_Boylan](#):
>
> Computing derivatives analytically is not at all appealing for the real problem.

You could do that for part of the code that fails, and possibly contribute a rule, see

[https://juliadiff.org/ChainRulesCore.jl/stable/](https://juliadiff.org/ChainRulesCore.jl/stable/)

and the tutorial section on matrix rules.
