# ChatGPT wrote this basedon the prompt
# I'm teaching a class in computational optimization that wants a demo of sparse direct methods. Can you come up with a fun Julia example to show off a sparse lu or cholesky factorization. Maybe throw in a few spy plots to illustrate the sparsity patterns of the factors and the fill in?
using SparseArrays
using LinearAlgebra
using SuiteSparse
using Plots
# Create a 2D finite difference Laplacian matrix on an n x n grid
function poisson_2d(n)
e = ones(n)
T = spdiagm(-1 => -e, 0 => 2e, 1 => -e)
I = spdiagm(0 => ones(n))
return kron(I, T) + kron(T, I)
end
# Visualize the sparsity pattern
function spyplot(A, title_str)
spy(A, markersize=1)
title!(title_str)
end
n = 10 # Grid size, gives n^2 x n^2 matrix
A = poisson_2d(n) # Sparse symmetric positive definite matrix
spyplot(A, "original")
# Cholesky factorization
F = cholesky(A + I)
L = F.L
SparseArrays.CHOLMOD.FactorComponent{Float64, :L, Int64}
type: LLt
method: simplicial
maxnnz: 783
nnz: 783
success: true
spyplot(sparse(L), "Cholesky Factor L (with Fill-In)")
# LU factorization (non-symmetric version for fun)
A_nonsym = copy(A)
A_nonsym[1, end] = 0.1 # Break symmetry
F_lu = lu(A_nonsym)
# Show LU factors
plot(layout=(1,2), size=(800,400))
plot!(1, spy(sparse(F_lu.L), markersize=1), title="LU Factor L")
plot!(2, spy(sparse(F_lu.U), markersize=1), title="LU Factor U")
MethodError: no method matching getindex(::Nothing, ::Int64)
The function `getindex` exists, but no method is defined for this combination of argument types.
Stacktrace:
[1] _apply_type_recipe(plotattributes::Any, v::Any, letter::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/type_recipe.jl:24
[2] macro expansion
@ ~/.julia/packages/RecipesPipeline/BGM3l/src/user_recipe.jl:131 [inlined]
[3] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, x::Any, y::Any)
@ RecipesPipeline ~/.julia/packages/RecipesBase/BRe07/src/RecipesBase.jl:300
[4] _process_userrecipes!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/user_recipe.jl:38
[5] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/RecipesPipeline.jl:72
[6] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
@ Plots ~/.julia/packages/Plots/Ec1L1/src/plot.jl:223
[7] plot!(::Plots.Plot, ::Any, ::Vararg{Any}; kw...)
@ Plots ~/.julia/packages/Plots/Ec1L1/src/plot.jl:213
[8] plot!(::Any, ::Vararg{Any}; kw...)
@ Plots ~/.julia/packages/Plots/Ec1L1/src/plot.jl:202
[9] top-level scope
@ In[4]:8
plot(spy(sparse(F_lu.L)), spy(sparse(F_lu.U)))
Abad = sprand(150,150,0.05)
150×150 SparseMatrixCSC{Float64, Int64} with 1125 stored entries:
⎡⠄⣀⠆⡁⠠⠀⠤⠀⠸⠀⠈⠈⠃⠀⢠⢀⠢⡀⡀⡂⠀⠠⠀⡒⢀⡁⢀⡔⠂⠀⠁⠐⠄⠐⠠⠆⠄⠁⠀⡂⎤
⎢⢀⠀⠂⢄⠀⠤⠢⠀⠀⠀⢄⡂⠀⠁⢍⠈⢀⠆⡀⡀⢅⠂⢀⠑⠀⠠⣀⠌⠀⠢⢀⡄⠀⠨⠠⢀⡤⠠⡈⡈⎥
⎢⠂⠁⡲⠁⠅⠀⠈⠈⡀⠐⠀⢀⠐⠀⠁⠀⡀⠠⠖⠀⠈⠀⠀⡀⠄⠀⡂⠠⢀⠂⠁⠈⠀⢐⠂⠁⢄⡈⠆⠀⎥
⎢⠂⠀⢠⠀⡂⠨⣀⠠⣌⢀⠁⠄⠕⠀⠄⣀⢂⡊⠀⠀⠀⠈⠐⡙⢁⠉⡣⡐⠁⠠⠀⠀⠑⠀⠠⢡⣀⠁⡁⠠⎥
⎢⠀⢒⠠⡁⡂⢂⠀⠀⡆⠃⠑⡁⡀⠨⡀⡂⢈⠅⢂⡑⠀⠀⢐⢀⠀⠨⠀⠁⠠⠀⡔⠀⡀⡆⠀⠀⠀⠰⠈⠑⎥
⎢⢠⠀⡁⠤⠈⢂⠐⠠⠀⢐⣀⠀⠨⠠⡅⠈⠐⠨⢄⠈⡀⡂⢄⠑⢆⣀⡀⠀⠀⠀⡄⠤⠀⠀⢢⠨⡂⠕⠈⠁⎥
⎢⠀⠈⠀⠄⠀⡀⠈⡆⠀⢘⠂⠁⠁⠀⡉⠐⡀⠂⠀⡀⠀⡨⠠⢊⡀⢀⡈⡀⣐⡰⡄⡠⠀⠀⡀⠀⠀⠠⡒⠆⎥
⎢⠀⠀⡈⠀⡒⠈⡖⠢⣁⠄⠄⠂⡀⠀⠃⢆⠀⠈⠔⠀⠂⢀⠈⣀⠀⢀⠀⠄⠣⢀⠂⠨⢀⠤⠰⢀⠈⠄⢠⠂⎥
⎢⠈⢩⠐⠈⠃⠂⠠⡕⠄⠀⠅⢀⠂⠀⢘⠀⠐⢀⠀⠤⡁⠀⠀⠀⠀⠀⠎⠠⠜⢈⠠⠨⠀⠃⠔⠐⠢⠐⡁⠐⎥
⎢⢀⢈⠢⠁⡇⢭⠓⠀⡀⠀⠂⡐⣈⠀⠠⠔⢠⠂⠀⣀⡐⡄⡈⠊⡂⠨⠀⠀⠠⡀⡐⠈⣐⡀⢁⠐⠃⠉⠘⠕⎥
⎢⠂⡁⠀⢀⡀⢀⠐⢌⡁⡀⠀⠙⠐⠁⡠⢀⠀⡁⢀⠴⠐⠂⢐⠒⠁⣀⡨⡀⠐⠊⠠⠀⠂⠢⠘⠹⡡⠄⠀⠁⎥
⎢⠀⡠⢂⠀⠀⠀⠰⡠⡄⠀⡰⠓⣰⠔⢀⠀⠀⠂⠂⠂⠂⠁⠄⢐⠀⢄⠂⠄⡀⠄⠂⠖⢄⡐⠶⠁⠀⠒⢀⠀⎥
⎢⠈⠐⠀⢌⠀⢂⢈⢈⢉⠠⠄⡂⠁⡠⠂⠠⡰⠁⡘⠐⠂⠁⠀⣇⠀⠀⠄⠀⠃⠀⠄⠀⠀⠆⠈⢚⠄⢉⡠⠀⎥
⎢⡄⠀⠀⠅⠠⠂⠠⣄⠀⠤⠠⠄⢁⠀⠀⠀⢁⠀⠈⢑⢈⠀⣀⡈⠀⠈⡀⢉⠖⠐⠐⠈⠀⠀⠀⡈⠈⢀⠁⠀⎥
⎢⠀⣀⡦⠐⠡⠩⠀⠀⣁⢀⠂⠥⢄⢈⠑⠁⠀⡀⠠⢅⡀⠈⡂⡄⡀⡈⠀⠨⡂⠂⡈⢀⠈⠀⠀⠀⣠⡤⠈⠱⎥
⎢⢄⡨⢨⠁⠅⠈⡂⠀⢀⡠⢀⢀⡀⠂⡁⠢⠀⡰⠇⠘⠀⠴⠀⠁⣇⠂⣀⠠⠀⢠⡠⡀⣁⠄⢀⠄⠀⠀⠍⡀⎥
⎢⠀⠀⠀⠣⠀⠘⠔⠔⢀⠁⠰⢲⢈⡠⠀⡈⠡⠀⠀⠔⢀⠌⠀⠄⠇⠆⡤⠰⠌⠜⠂⠄⠄⡠⢠⠀⡠⠀⠀⡈⎥
⎢⢣⠂⠈⠁⡠⢐⠘⠀⢐⡈⠙⠓⠀⢀⠆⠀⠁⡀⠀⠀⠈⠀⠈⠐⠀⠀⠀⢀⢀⠋⠀⠒⠂⠀⡀⠀⢘⣀⢐⡀⎥
⎢⠀⢈⠄⠔⠀⠈⠔⣁⡤⢀⡄⠒⠐⠀⠌⠄⠀⠀⠀⠑⠈⠂⠈⠑⠠⠁⠀⠆⠀⠀⠐⠄⠂⠁⠂⠀⠛⡐⠈⠂⎥
⎣⠑⠈⡈⢀⠀⠀⠀⠃⠀⠀⠨⠆⠀⠀⡀⠈⠂⠀⠄⠄⠔⢀⠐⠄⠁⠁⠀⠬⠢⠀⠀⠀⡂⠢⠱⠀⠐⢀⡤⠀⎦
F_bad = lu(Abad)
#plot(spy(sparse(F_lu.L)), spy(sparse(F_lu.U)))
F_lu.L
SingularException(0)
Stacktrace:
[1] #lu#7
@ /Applications/Julia-1.11.app/Contents/Resources/julia/share/julia/stdlib/v1.11/SparseArrays/src/solvers/umfpack.jl:389 [inlined]
[2] lu(S::SparseMatrixCSC{Float64, Int64})
@ SparseArrays.UMFPACK /Applications/Julia-1.11.app/Contents/Resources/julia/share/julia/stdlib/v1.11/SparseArrays/src/solvers/umfpack.jl:384
[3] top-level scope
@ In[7]:1
n = 100 # Grid size, gives n^2 x n^2 matrix
Abig = poisson_2d(n) # Sparse symmetric positive definite matrix
Abig
10100×10100 SparseMatrixCSC{Float64, Int64} with 50099 stored entries:
⎡⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⎦
Fbig = cholesky(Abig+I)
sparse(Fbig.L)
10100×10100 SparseMatrixCSC{Float64, Int64} with 373145 stored entries:
⎡⣳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⣀⣘⣳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⢈⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠠⠄⠸⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠠⠄⠤⠠⠿⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠩⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠚⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠒⠂⠒⠂⠒⠒⠒⠚⠛⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⢓⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣈⣳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠙⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⢱⣄⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠳⣄⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠷⣄⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⣀⣀⢀⣀⣀⣘⣳⣄⠀⠀⎥
⎣⣠⣤⢤⣤⠴⠶⠶⠦⢤⣶⣖⡦⠴⠖⠆⠐⠶⠒⢲⠿⠿⠛⠛⠻⠿⣡⣿⠛⠛⠉⠛⠚⢉⡁⣓⡚⠉⢘⣷⣄⎦