In [10]:
# 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")
Out[10]:
In [11]:
# Cholesky factorization
F = cholesky(A + I)
L = F.L
Out[11]:
SparseArrays.CHOLMOD.FactorComponent{Float64, :L, Int64}
type:    LLt
method:  simplicial
maxnnz:  783
nnz:     783
success: true
In [17]:
nnz(sparse(L))
Out[17]:
783
In [12]:
spyplot(sparse(L), "Cholesky Factor L (with Fill-In)")
Out[12]:
In [15]:
# what happens without the ordering
Fdense = cholesky(Matrix(A+I)) 
spyplot(sparse(Fdense.U),"dense cholesky")
Out[15]:
In [16]:
nnz(sparse(Fdense.U))
Out[16]:
1119
In [9]:
# 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!(spy(sparse(F_lu.L), markersize=1), title="LU Factor L")
    plot!(spy(sparse(F_lu.U), markersize=1), title="LU Factor U")
Out[9]:
In [5]:
plot(spy(sparse(F_lu.L)), spy(sparse(F_lu.U)))
Out[5]:
In [30]:
Abad = sprand(300,300,10/300)
Out[30]:
300×300 SparseMatrixCSC{Float64, Int64} with 3023 stored entries:
⎡⠀⡨⠲⢮⢥⠓⡐⡀⠄⣷⡉⢀⢢⡛⢚⡰⡞⢧⢨⡒⣇⠼⡺⢶⡈⡃⠗⣠⣠⡂⠂⢲⣦⢰⡐⡤⠦⢈⠄⠥⎤
⎢⡤⣡⠁⢅⢅⢪⡏⣊⢰⠇⠐⠯⣊⠬⣊⡴⣦⣙⡢⡮⡧⡹⠉⡦⡷⡢⣣⠅⠴⠛⠎⠤⠆⡡⡡⢧⠐⢈⡁⡄⎥
⎢⠤⠧⠈⡁⠋⣶⡈⠞⣕⠘⠈⡁⢨⠪⢅⠆⠦⢠⠄⢆⠑⢉⣊⢄⡡⡁⣂⢌⠌⠜⠰⢀⢀⡞⢑⢆⣊⢸⡋⠑⎥
⎢⢀⢂⡂⢡⠏⡠⠿⠀⣒⡄⠃⡞⢳⢤⠝⣉⡟⢕⠠⣒⠚⠃⣀⡂⠔⡰⠀⡈⠋⢪⣌⠏⣀⢋⠩⡤⡅⢻⣃⢂⎥
⎢⣭⠠⡮⡰⣌⠜⠂⢈⡡⢊⠇⢋⢗⣩⠉⠘⠝⡺⠷⠐⣅⠐⠪⢖⡫⡂⡀⣂⣽⢐⢒⣒⠄⠞⣒⠂⢀⠚⢉⠄⎥
⎢⠂⠅⠁⠩⢏⠓⡷⠋⣱⡄⠍⠦⡢⣥⢶⠩⢟⠞⠢⠔⡃⠏⠈⢅⢝⢵⡾⡁⠢⢘⢙⢔⡍⡅⠡⠩⡃⠝⢉⠂⎥
⎢⠢⠋⡡⣓⡊⠐⣉⣀⠜⣧⢞⡐⡾⢧⠀⡦⠢⢔⣂⡄⡠⠻⢕⠆⣃⠉⡖⡎⡠⡧⠤⢍⡠⠹⣲⠣⣇⡐⣿⡃⎥
⎢⢰⢭⢑⠲⡉⠥⣼⢰⠠⠏⠆⡓⠲⠀⠄⠗⢁⣇⠃⡨⠸⣡⡕⢃⠔⡄⠥⠗⠜⣐⠠⡔⢀⣸⡐⢢⢁⢀⠗⠍⎥
⎢⠠⡊⢣⢈⢜⠤⣀⢘⢌⣡⡢⠀⠃⢒⠭⢡⣀⢐⢁⠩⡘⡾⢄⠌⠤⠑⣡⡈⢩⠕⡘⡒⠢⠧⠗⢀⡏⢂⢲⠐⎥
⎢⣨⡤⢄⠉⡧⠵⠠⢺⠮⡀⢁⣘⠓⡵⣅⡄⡧⡀⢀⠂⠄⠄⡕⢌⢂⣋⠿⣀⠀⢀⠐⡳⡈⡃⡘⢨⠦⠈⣲⡆⎥
⎢⣙⡑⡁⢨⡒⢀⠀⢀⡃⡒⠞⣑⢫⠑⢍⠕⡏⢛⢈⡈⢇⢉⣐⣈⢸⡘⠁⠒⢊⠂⣀⡠⢓⠍⣢⣘⡆⢹⡈⠄⎥
⎢⢂⢝⡵⠸⣃⢡⡚⡀⣘⡏⠉⡒⠮⣬⡙⡋⠂⢙⡐⣐⡦⡃⣂⢕⢖⠁⠇⢩⠤⡇⠁⢑⠅⢝⢒⢑⢊⣣⡄⠁⎥
⎢⢤⠠⢀⠐⢂⠈⠌⡈⠕⢀⠌⠀⡈⠙⣰⢎⢗⣸⠣⠩⠊⡢⡃⠭⠟⢇⠊⠕⠐⣄⠠⠰⠘⣠⠌⢋⠈⢨⡌⡃⎥
⎢⠑⠄⢠⠊⡐⢞⢜⣈⣊⠃⢩⠞⡄⢆⠉⠃⡊⢽⢌⣌⠈⠢⢓⡽⠄⠻⢇⢄⠢⢎⢓⢁⣟⡆⡣⠆⠰⠐⠃⢣⎥
⎢⠎⠤⠄⣺⣀⣬⢸⢢⢰⢆⢵⡰⡆⣽⠝⠣⠥⢿⡆⠨⣧⠑⠐⠧⢯⡈⠄⡤⠨⠁⣑⠲⡇⡆⣗⠡⣅⢂⠀⡃⎥
⎢⡊⢨⢙⡀⢃⣤⡂⠌⢄⢠⡚⠥⢅⢈⠁⠪⠫⣌⢷⡡⠧⠔⢇⣔⠐⢽⢣⣇⢐⣄⣠⡈⡁⠬⢿⠈⣑⠄⡢⢄⎥
⎢⡾⢔⢣⡈⢀⠂⡫⢄⣸⠜⣝⠥⡰⠸⠢⠡⡑⠢⠣⡀⡠⠄⠈⠝⣘⡂⡭⠵⡸⠚⡔⠈⡹⢑⣒⠈⢋⡂⣥⡁⎥
⎢⢈⢮⠀⣂⢂⠪⢀⢴⠉⢃⠕⢃⣄⡜⡰⠴⠣⣬⠞⡣⣡⡘⠘⠲⡰⣡⣉⡘⠰⠐⢈⣂⢢⠆⣺⠒⠍⢦⢪⠢⎥
⎢⢣⢐⠗⠚⡅⠒⢬⠤⠢⡁⢂⢅⠀⠙⢽⠽⠇⡀⢦⡤⠄⠨⡳⠋⠘⠟⠢⠥⢰⡂⣕⠱⠊⠩⡁⢀⡒⠐⡊⠅⎥
⎣⡢⠿⠅⠩⠋⠚⢘⡄⠇⠂⠦⢶⠼⠌⢛⠘⣨⡼⠌⠃⠘⠄⢌⠟⡎⠰⠨⣡⡪⢗⢆⡒⣪⡁⣬⠁⠆⣔⡤⠀⎦
In [31]:
F_bad = lu(Abad+10I)
#plot(spy(sparse(F_lu.L)), spy(sparse(F_lu.U)))
F_bad.L
Out[31]:
300×300 SparseMatrixCSC{Float64, Int64} with 19062 stored entries:
⎡⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠀⠓⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠄⡄⢊⠵⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⢑⠠⢐⠀⠉⠨⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠠⢬⠐⠤⠀⠄⠡⠄⡵⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠁⠐⠸⠥⢴⠤⣒⡝⢭⢕⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⡂⠚⢉⢠⣀⠡⠸⣠⣒⢼⢱⣵⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠜⢑⠐⣴⢂⣣⣚⠲⣽⣭⣳⣶⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠁⣡⢁⣨⡄⡙⡬⣡⡉⣫⣉⣫⣽⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⡠⡆⢀⠉⠇⠦⡭⡩⣼⢧⡦⡵⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⢐⠈⢦⠠⠩⠱⠊⢐⢚⣳⡼⠛⢟⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠈⢒⠀⣧⠀⠭⡏⢟⣢⣾⢿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠠⣥⠥⠒⠒⠗⠛⣬⢚⣿⡿⣛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⢦⡐⢀⠋⠄⣃⡢⣾⠟⡗⡿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠄⢈⡭⢀⠪⡶⢼⠨⡧⣻⣿⣿⣯⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⢀⢀⠘⡡⢠⣀⣮⢠⣻⠡⣥⣦⣩⣭⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠡⡔⠡⣀⠠⠊⡬⠃⢽⣩⡠⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⎥
⎢⡀⢣⢀⠳⡐⢩⡀⡣⡉⠜⡅⣟⣩⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⎥
⎢⠔⠀⠊⡠⠠⣈⣸⠀⡇⣴⣵⣁⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⎥
⎣⠐⣂⡄⠨⠊⢟⡮⢭⠻⢿⣿⢷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⎦
In [8]:
n = 100            # Grid size, gives n^2 x n^2 matrix
Abig = poisson_2d(n)  # Sparse symmetric positive definite matrix

Abig
Out[8]:
10100×10100 SparseMatrixCSC{Float64, Int64} with 50099 stored entries:
⎡⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⎦
In [9]:
Fbig = cholesky(Abig+I)
sparse(Fbig.L)
Out[9]:
10100×10100 SparseMatrixCSC{Float64, Int64} with 373145 stored entries:
⎡⣳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⣀⣘⣳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⢈⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠠⠄⠸⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠠⠄⠤⠠⠿⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠩⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠚⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠒⠂⠒⠂⠒⠒⠒⠚⠛⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⢓⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣈⣳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠙⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⢱⣄⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠳⣄⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠷⣄⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⣀⣀⢀⣀⣀⣘⣳⣄⠀⠀⎥
⎣⣠⣤⢤⣤⠴⠶⠶⠦⢤⣶⣖⡦⠴⠖⠆⠐⠶⠒⢲⠿⠿⠛⠛⠻⠿⣡⣿⠛⠛⠉⠛⠚⢉⡁⣓⡚⠉⢘⣷⣄⎦