BandedMatrices.jl
BandedMatrices.jl copied to clipboard
LU decomposition
I needed to invert large banded matrices, and I found that BandedMatrices.jl didn't support this operation. For example:
julia> using LinearAlgebra
julia> using BandedMatrices
julia> B = brand(Int8, 5, 5, 2, 2)
5×5 BandedMatrix{Int8} with bandwidths (2, 2):
68 -17 -36 ⋅ ⋅
2 -88 -118 83 ⋅
83 8 -47 52 83
⋅ -6 -44 -116 98
⋅ ⋅ 57 -104 -87
julia> lu(B)
BandedMatrices.BandedLU{Float64, BandedMatrix{Float64, Matrix{Float64}, Base.OneTo{Int64}}}
L factor:
5×5 Matrix{Float64}:
1.0 0.0 0.0 0.0 0.0
0.0240964 1.0 0.0 0.0 0.0
5.7603e-16 -1.33319e-16 1.0 0.0 0.0
-3.15648e-16 0.0680328 -0.632442 1.0 0.0
0.819277 0.267077 0.591554 0.0155523 1.0
U factor:
5×5 BandedMatrix{Float64} with bandwidths (2, 4):
83.0 8.0 -47.0 52.0 83.0
0.0 -88.1928 -116.867 81.747 -2.0
0.0 0.0 57.0 -104.0 -87.0
⋅ 0.0 0.0 -187.335 43.1136
⋅ ⋅ 0.0 0.0 -16.6712
This uses a full matrix to store L, which is not good for me.
Similarly, when using rational numbers, I found that
julia> B = Rational{BigInt}.(brand(Int8, 5, 5, 2, 2))
5×5 BandedMatrix{Rational{BigInt}} with bandwidths (2, 2):
-128//1 -64//1 74//1 ⋅ ⋅
27//1 113//1 115//1 -88//1 ⋅
-10//1 87//1 51//1 -106//1 -67//1
⋅ -6//1 -48//1 -43//1 -47//1
⋅ ⋅ 29//1 -93//1 71//1
julia> lu(B)
ERROR: UndefVarError: banded_lufact! not defined
I have taken the liberty of implementing the functionality that I need outside of BandedMatrices.jl. See here for the functions I implemented.
The respective functionality is good enough for me, but is not quite generic. For example, I implemented \ to solve a linear system, but not an in-place ldiv!. These functions also don't support a banded RHS for \.
I would be happy to contribute this to BandedMatrices.jl. If you are interested, then please let me know how this could/should be integrated into your package. Otherwise, feel free to copy the code I wrote. This code is inspired (copied/translated) from Wikipedia (see the URL above), LAPACK (dtrsm), and the Julia LinearAlgebra package.
Yes please! I believe the issue is that LU is currently only implemented in LAPACK so a Julia native implementation would be fantastic
I've looked at the code for LU decomposition in BandedMatrices.jl, and it's not clear to me which part of the code would need to stay and which part should be rewritten. It seems that some LU decomposition functionality is there, but it's not implemented in an ideal way – e.g. it seems the L factor is full instead of banded.
- Is the type
BandedLUnecessary? It seems that the BaseLUtype would suffice. - Should the pivot search remain? A pivot search destroys the band structure. One could remove it, and ask people to convert to a full matrix if they want a pivot search.
- I am interested in supporting types that are not supported by LAPACK. Would it make sense to remove the calls to LAPACK, implementing the respective functions in Julia?
- A comment in the function
lu!states "l of the bands are ignored and overwritten". That seems weird. The problem seems to be that the LAPACK functiondgbsvallows (and here requires) over-allocating storage, which is not supported by this package. If there is no functionality to resize banded matrices without de-allocating storage, then filling the extra bands with zeros might be a good approach?
I suggest you read the docs on LAPACK's gbtrf:
https://netlib.org/lapack/explore-html/d2/d2d/group__double_g_bcomputational_ga7fc91ba3f250ad3844eba25d59f5d7be.html
Is the type BandedLU necessary? It seems that the Base LU type would suffice.
Yes since gbtrf does not actually permute the rows in memory (as that would destroy banded structure), instead it just records where the pivots were. So it's not the same format as LinearAlgebra.LU.
Should the pivot search remain? A pivot search destroys the band structure. One could remove it, and ask people to convert to a full matrix if they want a pivot search.
Yes because you maintain bandedness if you do what LAPACK does.
I am interested in supporting types that are not supported by LAPACK. Would it make sense to remove the calls to LAPACK, implementing the respective functions in Julia?
No, still use LAPACK for BLAS types. Only use the Julia implementation for general types. You can use BigFloat as a test.
A comment in the function lu! states "l of the bands are ignored and overwritten". That seems weird. The problem seems to be that the LAPACK function dgbsv allows (and here requires) over-allocating storage, which is not supported by this package. If there is no functionality to resize banded matrices without de-allocating storage, then filling the extra bands with zeros might be a good approach?
I don't agree: we do allow overallocating storage, e.g., if the data is a (strided) view of a bigger array.
Hi, FYI: I did some similar job for dgemm etc in sparspak: https://github.com/PetrKryslUCSD/Sparspak.jl/blob/main/src/Utilities/GenericBlasLapackFragments.jl
This was based on the netlib fortran code.