In my code, I have to solve a large sparse linear system (14000 x 14000) many times to integrate a stiff system of ODE.
Since the memory allocation by the backslash operator \
is quite large, I thought of manually performing LU factorization with pre-allocated arrays.
However, a significant amount of memory allocation is still there and I wanted to know if there is a way to eliminate it.
A minimal example of this problem is the following:
julia> using LinearAlgebra;
julia> using SparseArrays;
julia> using SuiteSparse.UMFPACK;
julia> using BenchmarkTools;
julia> A = sparse(Float64[1.0 2.0; 0.0 3.0]);
julia> F = lu(A)
UmfpackLU{Float64, Int64}
L factor:
2×2 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
1.0 ⋅
⋅ 1.0
U factor:
2×2 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
0.333333 0.666667
⋅ 1.0
julia> B = sparse(Float64[1.0 1.0; 0.0 1.0]);
julia> function lu_loop!(F::UmfpackLU, B::SparseMatrixCSC)
for _=1:2000
lu!(F,B)
end
end
lu_loop! (generic function with 1 method)
julia> @btime lu_loop!(F,B)
6.459 ms (72000 allocations: 4.23 MiB)
Now I think that pre-allocating F
could eliminate the allocations:
julia> mutable struct Factor
F::UmfpackLU
end
julia> factor = Factor(F)
Factor(UmfpackLU{Float64, Int64}(Ptr{Nothing} @0x00007fd428caeea0, Ptr{Nothing} @0x00007fd3f8c1e9b0, 2, 2, [0, 1, 3], [0, 0, 1], [1.0, 1.0, 1.0], 0))
julia> @btime lu_loop!(factor.F,B)
6.359 ms (72000 allocations: 4.23 MiB)
This does not seem to help at all (maybe I’m doing this wrong).
In my code, the allocation goes up to ~30GiB (I don’t know how it is even possible when I have 16GB of RAM) and I am wondering how I can avoid such a large amount of allocations.
If I can simply use the backslash operator \
, that would be better for readability but it allocates 2-3 times more.
Any idea why this is happening? Any feedback would be very much appreciated.