# Wrapping LAPACK functions using MKL

**URL:** <https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 9, 2023, 3:55pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997 "2023-11-09T15:55:29Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![andreasvarga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasvarga/32/11634_2.png) [@andreasvarga](https://discourse.julialang.org/u/andreasvarga)\
**Post date:** [November 9, 2023, 3:55pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/1 "2023-11-09T15:55:29Z")

</div>

The following implements a wrapper to the LAPACK functions dlanv2/slanv2:

```julia
import LinearAlgebra.BLAS.@blasfunc

using LinearAlgebra
import LinearAlgebra: libblastrampoline, BlasFloat, BlasReal, BlasComplex, BlasInt

const liblapack = Base.liblapack_name

for (fn, elty) in ((:dlanv2_, :Float64),
                   (:slanv2_, :Float32))
                   
    @eval begin
        function lanv2(A::$elty, B::$elty, C::$elty, D::$elty)
           """
           SUBROUTINE DLANV2( A, B, C, D, RT1R, RT1I, RT2R, RT2I, CS, SN )

           DOUBLE PRECISION A, B, C, CS, D, RT1I, RT1R, RT2I, RT2R, SN
           """
           RT1R = Ref{$elty}(1.0)
           RT1I = Ref{$elty}(1.0)
           RT2R = Ref{$elty}(1.0)
           RT2I = Ref{$elty}(1.0)
           CS = Ref{$elty}(1.0)
           SN = Ref{$elty}(1.0)
           ccall((@blasfunc($fn), liblapack), Cvoid,
                 (Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty},
                 Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty}),
                 A, B, C, D,
                 RT1R, RT1I, RT2R, RT2I, CS, SN)
           return RT1R[], RT1I[], RT2R[], RT2I[], CS[], SN[]
        end
    end
end
"""
    lanv2(A, B, C, D) -> (RT1R, RT1I, RT2R, RT2I, CS, SN)

Compute the Schur factorization of a real 2-by-2 nonsymmetric matrix `[A,B;C,D]` in
standard form. `A`, `B`, `C`, `D` are overwritten on output by the corresponding elements of the
standardised Schur form. `RT1R+im*RT1I` and `RT2R+im*RT2I` are the resulting eigenvalues.
`CS` and `SN` are the parameters of the rotation matrix.
Interface to the LAPACK subroutines DLANV2/SLANV2.
"""
lanv2(A::BlasReal, B::BlasReal, C::BlasReal, D::BlasReal)

```

I can call `lanv2` and get the correct result

```julia
julia> lanv2(1.,2.,3.,4.)
(-0.3722813232690143, 0.0, 5.372281323269014, 0.0, -0.8245648401323938, 0.5657674649689923)

```

After loading `MKL`, I get an error message and wrong results:

```julia
julia> using MKL

julia> lanv2(1.,2.,3.,4.)
Error: no BLAS/LAPACK library loaded!
(1.0, 1.0, 1.0, 1.0, 1.0, 1.0)

```

I wonder what is wrong with my interface. It would be desirable that this routine works with both OpenBLAS and MKL.

---

<div class="post-metadata">

**Author:** ![MichelJuillard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/micheljuillard/32/10555_2.png) [@MichelJuillard](https://discourse.julialang.org/u/MichelJuillard)\
**Post date:** [November 9, 2023, 4:06pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/2 "2023-11-09T16:06:57Z")

</div>

In [GitHub - DynareJulia/FastLapackInterface.jl](https://github.com/DynareJulia/FastLapackInterface.jl) we use

```julia
@static if VERSION < v"1.7"
    using LinearAlgebra.LAPACK: liblapack
elseif VERSION < v"1.9"
    const liblapack = "libblastrampoline"
else
    const liblapack = LinearAlgebra.libblastrampoline
end

```

and it works with both OpenBlas and MKL

---

<div class="post-metadata">

**Author:** ![andreasvarga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasvarga/32/11634_2.png) [@andreasvarga](https://discourse.julialang.org/u/andreasvarga)\
**Post date:** [November 9, 2023, 4:18pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/3 "2023-11-09T16:18:11Z")

</div>

Thanks for hinting to this. However, I already tried the above code, but I doesn’t work for me (for some reason). In both cases, I obtained

`liblapack = "libblastrampoline-5.dll"`

Is this the expected output?

---

<div class="post-metadata">

**Author:** ![MichelJuillard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/micheljuillard/32/10555_2.png) [@MichelJuillard](https://discourse.julialang.org/u/MichelJuillard)\
**Post date:** [November 9, 2023, 4:30pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/4 "2023-11-09T16:30:55Z")

</div>

Yes, I get something similar under Linux. It is the `libblastrampoline` that loads OpenBlas or MKL at run time. See [GitHub - JuliaLinearAlgebra/libblastrampoline: Using PLT trampolines to provide a BLAS and LAPACK demuxing library.](https://github.com/JuliaLinearAlgebra/libblastrampoline)

---

<div class="post-metadata">

**Author:** ![andreasvarga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasvarga/32/11634_2.png) [@andreasvarga](https://discourse.julialang.org/u/andreasvarga)\
**Post date:** [November 10, 2023, 10:52am UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/5 "2023-11-10T10:52:09Z")

</div>

I still don’t understand the exact situation. Could it be that no interface to the LAPACK auxiliary function `dlanv2` (to compute the Schur form and eigenvalues of a 2x2 matrix) is provided in MKL or the interface is different from that provided by OpenBLAS?. I assume it is somehow possible to check this (perhaps can somebody execute the above tests in Linux!). I included the code with the proposed fix (not working for me), just in case somebody has time for a short check. Many thanks in advance.

```julia

import LinearAlgebra.BLAS.@blasfunc

using LinearAlgebra
import LinearAlgebra: libblastrampoline, BlasFloat, BlasReal, BlasComplex, BlasInt

using Base: iszero, has_offset_axes
using LinearAlgebra.LAPACK

#const liblapack = Base.liblapack_name

@static if VERSION < v"1.7"
    using LinearAlgebra.LAPACK: liblapack
elseif VERSION < v"1.9"
    const liblapack = "libblastrampoline"
else
    const liblapack = LinearAlgebra.libblastrampoline
end

for (fn, elty) in ((:dlanv2_, :Float64),
                   (:slanv2_, :Float32))
                   
    @eval begin
        function lanv2(A::$elty, B::$elty, C::$elty, D::$elty)
           """
           SUBROUTINE DLANV2( A, B, C, D, RT1R, RT1I, RT2R, RT2I, CS, SN )

           DOUBLE PRECISION A, B, C, CS, D, RT1I, RT1R, RT2I, RT2R, SN
           """
           RT1R = Ref{$elty}(1.0)
           RT1I = Ref{$elty}(1.0)
           RT2R = Ref{$elty}(1.0)
           RT2I = Ref{$elty}(1.0)
           CS = Ref{$elty}(1.0)
           SN = Ref{$elty}(1.0)
           ccall((@blasfunc($fn), liblapack), Cvoid,
                 (Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty},
                 Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty},Ref{$elty}),
                 A, B, C, D,
                 RT1R, RT1I, RT2R, RT2I, CS, SN)
           return RT1R[], RT1I[], RT2R[], RT2I[], CS[], SN[]
        end
    end
end

```

---

<div class="post-metadata">

**Author:** ![MichelJuillard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/micheljuillard/32/10555_2.png) [@MichelJuillard](https://discourse.julialang.org/u/MichelJuillard)\
**Post date:** [November 11, 2023, 5:00pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/6 "2023-11-11T17:00:26Z")

</div>

I can reproduce the problem in Linux. It seems specific to `lanv2` as I can compute `gqref` with a similar code. However, the way `lanv2` is packaged in MKL\_jll seems different from `gqref`  
If I look at the symbol in libmkl\_rt.so.2, I get:

```julia
michel@21HFCTO1WW:~/.julia/artifacts/347e4bf25d69805922225ce6bf819ef0b8715426/lib$ nm libmkl_rt.so.2 |grep dgeqrf
0000000000454840 T dgeqrf
0000000000454840 T dgeqrf_
0000000000454910 T dgeqrf_64
0000000000454910 T dgeqrf_64_
0000000000454b00 T dgeqrfp
0000000000454b00 T dgeqrfp_
0000000000454bd0 T dgeqrfp_64
0000000000454bd0 T dgeqrfp_64_
0000000000508310 T lapacke_dgeqrf
0000000000508310 T lapacke_dgeqrf_
0000000000508310 T LAPACKE_dgeqrf
0000000000508270 T lapacke_dgeqrf_64
0000000000508270 T lapacke_dgeqrf_64_
0000000000508270 T LAPACKE_dgeqrf_64
0000000000508610 T lapacke_dgeqrfp
0000000000508610 T lapacke_dgeqrfp_
0000000000508610 T LAPACKE_dgeqrfp
0000000000508570 T lapacke_dgeqrfp_64
0000000000508570 T lapacke_dgeqrfp_64_
0000000000508570 T LAPACKE_dgeqrfp_64
0000000000508790 T lapacke_dgeqrfp_work
0000000000508790 T lapacke_dgeqrfp_work_
0000000000508790 T LAPACKE_dgeqrfp_work
00000000005086b0 T lapacke_dgeqrfp_work_64
00000000005086b0 T lapacke_dgeqrfp_work_64_
00000000005086b0 T LAPACKE_dgeqrfp_work_64
0000000000508490 T lapacke_dgeqrf_work
0000000000508490 T lapacke_dgeqrf_work_
0000000000508490 T LAPACKE_dgeqrf_work
00000000005083b0 T lapacke_dgeqrf_work_64
00000000005083b0 T lapacke_dgeqrf_work_64_
00000000005083b0 T LAPACKE_dgeqrf_work_64
00000000004549e0 T mkl_dgeqrf_compact
00000000004549e0 T mkl_dgeqrf_compact_
0000000000454840 T mkl_lapack__dgeqrf_
0000000000454910 T mkl_lapack__dgeqrf_64_
00000000006b89c0 T mkl_lapack_dgeqrf_omp_offload_ilp64
00000000006b8ac0 T mkl_lapack_dgeqrf_omp_offload_ilp64_
00000000006b8dc0 T mkl_lapack_dgeqrf_omp_offload_lp64
00000000006b8ec0 T mkl_lapack_dgeqrf_omp_offload_lp64_
0000000000454b00 T mkl_lapack__dgeqrfp_
0000000000454bd0 T mkl_lapack__dgeqrfp_64_
00000000004549e0 T mkl_lapack__mkl_dgeqrf_compact_
michel@21HFCTO1WW:~/.julia/artifacts/347e4bf25d69805922225ce6bf819ef0b8715426/lib$ nm libmkl_rt.so.2 |grep dlanv2
0000000000466fe0 T dlanv2
0000000000466fe0 T dlanv2_
0000000000466fe0 T mkl_lapack__dlanv2_

```

I’m out of my depth here. Maybe you should open an issue on `MKL.jl`

---

<div class="post-metadata">

**Author:** ![andreasvarga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andreasvarga/32/11634_2.png) [@andreasvarga](https://discourse.julialang.org/u/andreasvarga)\
**Post date:** [November 11, 2023, 6:29pm UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/7 "2023-11-11T18:29:10Z")

</div>

Thank you for your time. The problem of non-uniform interface in MKL has been already addressed in this [issue](https://github.com/JuliaLinearAlgebra/MKL.jl/issues/138) and a PR is underway to fix it [JuliaLinearAlgebra/MKL.jl#140](https://github.com/JuliaLinearAlgebra/MKL.jl/pull/140). (not yet merged).

---

<div class="post-metadata">

**Author:** ![MichelJuillard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/micheljuillard/32/10555_2.png) [@MichelJuillard](https://discourse.julialang.org/u/MichelJuillard)\
**Post date:** [November 12, 2023, 5:30am UTC](https://discourse.julialang.org/t/wrapping-lapack-functions-using-mkl/105997/8 "2023-11-12T05:30:47Z")

</div>

👍
