Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SparseMatrixColorings"
uuid = "0a514795-09f3-496d-8182-132a7b665d35"
authors = ["Guillaume Dalle <22795598+gdalle@users.noreply.github.com>"]
version = "0.3.0"
version = "0.3.1"

[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Expand Down
45 changes: 28 additions & 17 deletions src/decompression.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ end
colors::AbstractVector{<:Integer}
) where {R<:Real}

Decompress the thin matrix `C` into a fat matrix `A` with the same sparsity pattern as `S`.
Decompress the thin matrix `C` into the fat matrix `A` which must have the same sparsity pattern as `S`.

Here, `colors` is a column coloring of `S`, while `C` is a compressed representation of matrix `A` obtained by summing the columns that share the same color.
"""
Expand All @@ -44,11 +44,12 @@ function decompress_columns!(
colors::AbstractVector{<:Integer},
) where {R<:Real}
A .= zero(R)
@views for j in axes(A, 2)
for j in axes(A, 2)
k = colors[j]
rows_j = map(!iszero, S[:, j])
copyto!(A[rows_j, j], C[rows_j, k])
A[rows_j, j] .= C[rows_j, k]
rows_j = (!iszero).(view(S, :, j))
Aj = view(A, rows_j, j)
Cj = view(C, rows_j, k)
copyto!(Aj, Cj)
end
return A
end
Expand All @@ -59,14 +60,18 @@ function decompress_columns!(
C::AbstractMatrix{R},
colors::AbstractVector{<:Integer},
) where {R<:Real}
# assume A and S have the same pattern
if nnz(parent(A)) != nnz(parent(S))
throw(DimensionMismatch("`A` and `S` must have the same sparsity pattern."))
end
Anz, Arv = nonzeros(A), rowvals(A)
Anz .= zero(R)
@views for j in axes(A, 2)
for j in axes(A, 2)
k = colors[j]
nzrange_j = nzrange(A, j)
rows_j = Arv[nzrange_j]
copyto!(Anz[nzrange_j], C[rows_j, k])
rows_j = view(Arv, nzrange_j)
Aj = view(Anz, nzrange_j)
Cj = view(C, rows_j, k)
copyto!(Aj, Cj)
end
return A
end
Expand Down Expand Up @@ -99,7 +104,7 @@ end
colors::AbstractVector{<:Integer}
) where {R<:Real}

Decompress the small matrix `C` into the tall matrix `A` with the same sparsity pattern as `S`.
Decompress the small matrix `C` into the tall matrix `A` which must have the same sparsity pattern as `S`.

Here, `colors` is a row coloring of `S`, while `C` is a compressed representation of matrix `A` obtained by summing the columns that share the same color.
"""
Expand All @@ -112,10 +117,12 @@ function decompress_rows!(
colors::AbstractVector{<:Integer},
) where {R<:Real}
A .= zero(R)
@views for i in axes(A, 1)
for i in axes(A, 1)
k = colors[i]
cols_i = map(!iszero, S[i, :])
copyto!(A[i, cols_i], C[k, cols_i])
cols_i = (!iszero).(view(S, i, :))
Ai = view(A, i, cols_i)
Ci = view(C, k, cols_i)
copyto!(Ai, Ci)
end
return A
end
Expand All @@ -126,15 +133,19 @@ function decompress_rows!(
C::AbstractMatrix{R},
colors::AbstractVector{<:Integer},
) where {R<:Real}
# assume A and S have the same pattern
if nnz(parent(A)) != nnz(parent(S))
throw(DimensionMismatch("`A` and `S` must have the same sparsity pattern."))
end
PA = parent(A)
PAnz, PArv = nonzeros(PA), rowvals(PA)
PAnz .= zero(R)
@views for i in axes(A, 1)
for i in axes(A, 1)
k = colors[i]
nzrange_i = nzrange(PA, i)
cols_i = PArv[nzrange_i]
copyto!(PAnz[nzrange_i], C[k, cols_i])
cols_i = view(PArv, nzrange_i)
Ai = view(PAnz, nzrange_i)
Ci = view(C, k, cols_i)
copyto!(Ai, Ci)
end
return A
end
Expand Down
101 changes: 76 additions & 25 deletions test/decompression_correctness.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,91 @@ rng = StableRNG(63)

algo = GreedyColoringAlgorithm()

m, n = 10, 20

A0 = sprand(rng, Bool, m, n, 0.3)
A1 = Matrix(A0)
A0t = transpose(A0)
A1t = transpose(A1)

S0 = map(!iszero, A0)
S1 = map(!iszero, A1)
S0t = transpose(S0)
S1t = transpose(S1)

@testset "Column decompression" begin
@testset "$(typeof(A))" for (A, S) in zip((A0, A1), (S0, S1))
colors = column_coloring(A, algo)
@testset "Small" begin
A0 = [
1 0 2
0 3 4
5 0 0
]
S0 = Bool[
1 0 1
0 1 1
1 0 0
]
C = [
1 2
3 4
5 0
]
colors = [1, 1, 2]
@testset "$(typeof(A)) - $(typeof(S))" for (A, S) in [
(A0, S0), #
(sparse(A0), sparse(S0)),
]
@test decompress_columns(S, C, colors) == A
end
end
@testset "Medium" begin
m, n = 18, 20
A0 = sprand(rng, Bool, m, n, 0.2)
S0 = map(!iszero, A0)
colors = column_coloring(A0, algo)
groups = color_groups(colors)
@test length(groups[1]) > 1
C = stack(groups) do group
dropdims(sum(A[:, group]; dims=2); dims=2)
C = stack(groups; dims=2) do group
dropdims(sum(A0[:, group]; dims=2); dims=2)
end
@test size(C) == (size(A0, 1), length(groups))
@testset "$(typeof(A)) - $(typeof(S))" for (A, S) in [
(A0, S0), #
(Matrix(A0), Matrix(S0)),
]
@test decompress_columns(S, C, colors) == A
end
A_new = decompress_columns(S, C, colors)
@test A_new == A
end
end

@testset "Row decompression" begin
@testset "$(typeof(At))" for (At, St) in zip((A0t, A1t), (S0t, S1t))
colors = row_coloring(At, algo)
@testset "Small" begin
A0 = [
1 0 3
0 2 0
4 5 0
]
S0 = Bool[
1 0 1
0 1 0
1 1 0
]
C = [
1 2 3
4 5 0
]
colors = [1, 1, 2]
@testset "$(typeof(A)) - $(typeof(S))" for (A, S) in [
(A0, S0), #
(transpose(sparse(transpose(A0))), transpose(sparse(transpose(S0)))),
]
@test decompress_rows(S, C, colors) == A
end
end
@testset "Medium" begin
m, n = 18, 20
A0 = sprand(rng, Bool, m, n, 0.2)
S0 = map(!iszero, A0)
A0t = transpose(A0)
S0t = transpose(S0)
colors = row_coloring(A0t, algo)
groups = color_groups(colors)
@test length(groups[1]) > 1
Ct = stack(groups; dims=1) do group
dropdims(sum(At[group, :]; dims=1); dims=1)
dropdims(sum(A0t[group, :]; dims=1); dims=1)
end
@test size(Ct) == (length(groups), size(A0t, 2))
@testset "$(typeof(At)) - $(typeof(St))" for (At, St) in [
(A0t, S0t), #
(Matrix(A0t), Matrix(S0t)),
]
@test decompress_rows(St, Ct, colors) == At
end
At_new = decompress_rows(St, Ct, colors)
@test At_new == At
end
end
4 changes: 2 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ using Test
include("decompression_correctness.jl")
end
end
@testset "Performance" begin
@testset verbose = true "Performance" begin
if VERSION >= v"1.10"
@testset "Coloring" begin
include("coloring_performance.jl")
end
end
end
@testset "Comparison" begin
@testset verbose = true "Comparison" begin
@testset "SuiteSparse" begin
include("suitesparse.jl")
end
Expand Down