From 2b57c481d3d8744e103af2bd1390969023787a09 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Wed, 17 Jul 2024 18:49:33 -0400 Subject: [PATCH] Add decompress_row! and decompress_column! --- src/SparseMatrixColorings.jl | 4 +- src/decompression.jl | 131 +++++++++++++++++++++++++++++++++-- test/small.jl | 20 ++++++ 3 files changed, 149 insertions(+), 6 deletions(-) diff --git a/src/SparseMatrixColorings.jl b/src/SparseMatrixColorings.jl index 38b4690d..480db692 100644 --- a/src/SparseMatrixColorings.jl +++ b/src/SparseMatrixColorings.jl @@ -43,8 +43,8 @@ include("check.jl") @compat public NaturalOrder, RandomOrder, LargestFirst @compat public color_groups -@compat public decompress_columns, decompress_columns! -@compat public decompress_rows, decompress_rows! +@compat public decompress_columns, decompress_columns!, decompress_column! +@compat public decompress_rows, decompress_rows!, decompress_row! @compat public decompress_symmetric, decompress_symmetric! @compat public StarSet diff --git a/src/decompression.jl b/src/decompression.jl index 2e5eb601..0e20ab38 100644 --- a/src/decompression.jl +++ b/src/decompression.jl @@ -74,6 +74,67 @@ function decompress_columns( return decompress_columns!(A, S, B, color) end +""" + decompress_column!( + A::AbstractMatrix{R}, + S::AbstractMatrix{Bool}, + v::AbstractVector{R}, + c::Int, + color::AbstractVector{<:Integer} + ) where {R<:Real} + +Decompress the column `v` associated to color `c` into the wide matrix `A` which must have the same sparsity pattern as `S`. + +Here, `color` is a column coloring of `S`, while `v` is obtained by summing the columns of `A` that share the same color `c`. +""" +function decompress_column! end + +function decompress_column!( + A::AbstractMatrix{R}, + S::AbstractMatrix{Bool}, + v::AbstractVector{R}, + c::Int, + color::AbstractVector{<:Integer}, +) where {R<:Real} + if !same_sparsity_pattern(A, S) + throw(DimensionMismatch("`A` and `S` must have the same sparsity pattern.")) + end + for j in axes(A, 2) + cj = color[j] + if cj == c + rows_j = (!iszero).(view(S, :, j)) + Aj = view(A, rows_j, j) + vj = view(v, rows_j) + copyto!(Aj, vj) + end + end + return A +end + +function decompress_column!( + A::SparseMatrixCSC{R}, + S::SparseMatrixCSC{Bool}, + v::AbstractVector{R}, + c::Int, + color::AbstractVector{<:Integer}, +) where {R<:Real} + if !same_sparsity_pattern(A, S) + throw(DimensionMismatch("`A` and `S` must have the same sparsity pattern.")) + end + Anz, Arv = nonzeros(A), rowvals(A) + for j in axes(A, 2) + cj = color[j] + if cj == c + nzrange_j = nzrange(A, j) + rows_j = view(Arv, nzrange_j) + Aj = view(Anz, nzrange_j) + vj = view(v, rows_j) + copyto!(Aj, vj) + end + end + return A +end + ## Row decompression """ @@ -86,7 +147,7 @@ end Decompress the small matrix `B` into the tall matrix `A` which must have the same sparsity pattern as `S`. -Here, `color` is a row coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the columns that share the same color. +Here, `color` is a row coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the rows that share the same color. """ function decompress_rows! end @@ -142,7 +203,7 @@ end Decompress the small matrix `B` into a new tall matrix `A` with the same sparsity pattern as `S`. -Here, `color` is a row coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the columns that share the same color. +Here, `color` is a row coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the rows that share the same color. """ function decompress_rows( S::AbstractMatrix{Bool}, B::AbstractMatrix{R}, color::AbstractVector{<:Integer} @@ -151,6 +212,68 @@ function decompress_rows( return decompress_rows!(A, S, B, color) end +""" + decompress_row!( + A::AbstractMatrix{R}, + S::AbstractMatrix{Bool}, + v::AbstractVector{R}, + c::Int, + color::AbstractVector{<:Integer} + ) where {R<:Real} + +Decompress the row `v` associated to color `c` into the tall matrix `A` which must have the same sparsity pattern as `S`. + +Here, `color` is a row coloring of `S`, while `v` is obtained by summing the rows that share the same color `c`. +""" +function decompress_row! end + +function decompress_row!( + A::AbstractMatrix{R}, + S::AbstractMatrix{Bool}, + v::AbstractVector{R}, + c::Int, + color::AbstractVector{<:Integer}, +) where {R<:Real} + if !same_sparsity_pattern(A, S) + throw(DimensionMismatch("`A` and `S` must have the same sparsity pattern.")) + end + for i in axes(A, 1) + ci = color[i] + if ci == c + cols_i = (!iszero).(view(S, i, :)) + Ai = view(A, i, cols_i) + vi = view(v, cols_i) + copyto!(Ai, vi) + end + end + return A +end + +function decompress_row!( + A::TransposeOrAdjoint{R,<:SparseMatrixCSC{R}}, + S::TransposeOrAdjoint{Bool,<:SparseMatrixCSC{Bool}}, + v::AbstractVector{R}, + c::Int, + color::AbstractVector{<:Integer}, +) where {R<:Real} + if !same_sparsity_pattern(A, S) + throw(DimensionMismatch("`A` and `S` must have the same sparsity pattern.")) + end + PA = parent(A) + PAnz, PArv = nonzeros(PA), rowvals(PA) + for i in axes(A, 1) + ci = color[i] + if ci == c + nzrange_i = nzrange(PA, i) + cols_i = view(PArv, nzrange_i) + Ai = view(PAnz, nzrange_i) + vi = view(v, cols_i) + copyto!(Ai, vi) + end + end + return A +end + ## Symmetric decompression """ @@ -164,7 +287,7 @@ end Decompress the narrow matrix `B` into the symmetric matrix `A` which must have the same sparsity pattern as `S`. -Here, `color` is a symmetric coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the columns that share the same color. +Here, `color` is a symmetric coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the rows / columns that share the same color. Decompression is faster when a [`StarSet`](@ref) is also provided. @@ -273,7 +396,7 @@ end Decompress the narrow matrix `B` into a new symmetric matrix `A` with the same sparsity pattern as `S`. -Here, `color` is a symmetric coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the columns that share the same color. +Here, `color` is a symmetric coloring of `S`, while `B` is a compressed representation of matrix `A` obtained by summing the rows / columns that share the same color. Decompression is faster when a [`StarSet`](@ref) is also provided. diff --git a/test/small.jl b/test/small.jl index cdbd7f18..23c39c68 100644 --- a/test/small.jl +++ b/test/small.jl @@ -7,8 +7,10 @@ using SparseMatrixColorings: color_groups, decompress_columns, decompress_columns!, + decompress_column!, decompress_rows, decompress_rows!, + decompress_row!, decompress_symmetric, decompress_symmetric!, matrix_versions, @@ -37,6 +39,15 @@ algo = GreedyColoringAlgorithm() matrix_versions(A0), matrix_versions(S0) ) @test decompress_columns(S, B, color) == A + + A2 = copy(A) + fill!(A2, 0) + ncolors = 2 + for c in 1:ncolors + decompress_column!(A2, S, B[:, c], c, color) + end + + @test A2 == A end end; @@ -56,6 +67,15 @@ end; matrix_versions(A0), matrix_versions(S0) ) @test decompress_rows(S, B, color) == A + + A2 = copy(A) + fill!(A2, 0) + ncolors = 2 + for c in 1:ncolors + decompress_row!(A2, S, B[c, :], c, color) + end + + @test A2 == A end end;