Skip to content

Commit

Permalink
Improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
gdalle committed Nov 8, 2024
1 parent be3b3b5 commit 637e5c9
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 28 deletions.
1 change: 1 addition & 0 deletions docs/src/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ SparseMatrixColorings.StarSetColoringResult
SparseMatrixColorings.TreeSetColoringResult
SparseMatrixColorings.LinearSystemColoringResult
SparseMatrixColorings.BicoloringResult
SparseMatrixColorings.remap_colors
```

## Testing
Expand Down
47 changes: 29 additions & 18 deletions src/decompression.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ function compress end
function compress(A, result::AbstractColoringResult{structure,:column}) where {structure}
group = column_groups(result)
B = stack(group; dims=2) do g
dropdims(sum(A[:, g]; dims=2); dims=2)
dropdims(sum(view(A, :, g); dims=2); dims=2)
end
return B
end

function compress(A, result::AbstractColoringResult{structure,:row}) where {structure}
group = row_groups(result)
B = stack(group; dims=1) do g
dropdims(sum(A[g, :]; dims=1); dims=1)
dropdims(sum(view(A, g, :); dims=1); dims=1)
end
return B
end
Expand All @@ -66,10 +66,10 @@ function compress(
row_group = row_groups(result)
column_group = column_groups(result)
Br = stack(row_group; dims=1) do g
dropdims(sum(A[g, :]; dims=1); dims=1)
dropdims(sum(view(A, g, :); dims=1); dims=1)
end
Bc = stack(column_group; dims=2) do g
dropdims(sum(A[:, g]; dims=2); dims=2)
dropdims(sum(view(A, :, g); dims=2); dims=2)
end
return Br, Bc
end
Expand Down Expand Up @@ -661,33 +661,44 @@ end

## BicoloringResult

function _reconstruct_B!(result::BicoloringResult, Br::AbstractMatrix, Bc::AbstractMatrix)
function _join_compressed!(result::BicoloringResult, Br::AbstractMatrix, Bc::AbstractMatrix)
#=
Say we have an original matrix `A` of size `(n, m)` and we build an augmented matrix `A_and_Aᵀ = [zeros(n, n) Aᵀ; A zeros(m, m)]`.
Its first `1:n` columns have the form `[zeros(n); A[:, j]]` and its following `n+1:n+m` columns have the form `[A[i, :]; zeros(m)]`.
The symmetric column coloring is performed on `A_and_Aᵀ` and the column-wise compression of `A_and_Aᵀ` should return a matrix `Br_and_Bc`.
But in reality, `Br_and_Bc` is computed as two partial compressions: the row-wise compression `Br` (corresponding to `Aᵀ`) and the columnwise compression `Bc` (corresponding to `A`).
Before symmetric decompression, we must reconstruct `Br_and_Bc` from `Br` and `Bc`, knowing that the symmetric colors (those making up `Br_and_Bc`) are present in either a row of `Br`, a column of `Bc`, or both.
Therefore, the column indices in `Br_and_Bc` don't necessarily match with the row indices in `Br` or the column indices in `Bc` since some colors may be missing in the partial compressions.
The columns of the top part of `Br_and_Bc` (rows `1:n`) are the rows of `Br`, interlaced with zero columns whenever the current color hasn't been used to color any row.
The columns of the bottom part of `Br_and_Bc` (rows `n+1:n+m`) are the columns of `Bc`, interlaced with zero columns whenever the current color hasn't been used to color any column.
We use the dictionaries `col_color_ind` and `row_color_ind` to map from symmetric colors to row/column colors.
=#
(; A, col_color_ind, row_color_ind) = result
m, n = size(A)
R = Base.promote_eltype(Br, Bc)
if eltype(result.B) == R
B = result.B
Br_and_Bc = result.Br_and_Bc
else
B = similar(result.B, R)
Br_and_Bc = similar(result.Br_and_Bc, R)
end
fill!(B, zero(R))
for c in axes(B, 2)
if haskey(col_color_ind, c) # some columns were colored with c
@views copyto!(B[(n + 1):(n + m), c], Bc[:, col_color_ind[c]])
fill!(Br_and_Bc, zero(R))
for c in axes(Br_and_Bc, 2)
if haskey(row_color_ind, c) # some rows were colored with symmetric color c
@views copyto!(Br_and_Bc[1:n, c], Br[row_color_ind[c], :])
end
if haskey(row_color_ind, c) # some rows were colored with c
@views copyto!(B[1:n, c], Br[row_color_ind[c], :])
if haskey(col_color_ind, c) # some columns were colored with symmetric c
@views copyto!(Br_and_Bc[(n + 1):(n + m), c], Bc[:, col_color_ind[c]])
end
end
return B
return Br_and_Bc
end

function decompress!(
A::AbstractMatrix, Br::AbstractMatrix, Bc::AbstractMatrix, result::BicoloringResult
)
m, n = size(A)
B = _reconstruct_B!(result, Br, Bc)
A_and_Aᵀ = decompress(B, result.symmetric_result)
Br_and_Bc = _join_compressed!(result, Br, Bc)
A_and_Aᵀ = decompress(Br_and_Bc, result.symmetric_result)
copyto!(A, A_and_Aᵀ[(n + 1):(n + m), 1:n]) # original matrix in bottom left corner
return A
end
Expand All @@ -697,10 +708,10 @@ function decompress!(
)
(; large_colptr, large_rowval, symmetric_result) = result
m, n = size(A)
B = _reconstruct_B!(result, Br, Bc)
Br_and_Bc = _join_compressed!(result, Br, Bc)
# pretend A is larger
A_and_noAᵀ = SparseMatrixCSC(m + n, m + n, large_colptr, large_rowval, A.nzval)
# decompress lower triangle only
decompress!(A_and_noAᵀ, B, symmetric_result, :L)
decompress!(A_and_noAᵀ, Br_and_Bc, symmetric_result, :L)
return A
end
31 changes: 21 additions & 10 deletions src/result.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ Return the number of different colors used to color the matrix.
For bidirectional partitions, this number is the sum of the number of row colors and the number of column colors.
"""
function ncolors(res::AbstractColoringResult{structure,:column}) where {structure}
return maximum(column_colors(res))
return length(column_groups(res))
end

function ncolors(res::AbstractColoringResult{structure,:row}) where {structure}
return maximum(row_colors(res))
return length(row_groups(res))
end

function ncolors(res::AbstractColoringResult{structure,:bidirectional}) where {structure}
return maximum(row_colors(res)) + maximum(column_colors(res))
return length(row_groups(res)) + length(column_groups(res))
end

"""
Expand Down Expand Up @@ -550,10 +550,21 @@ end

## Bicoloring result

"""
remap_colors(color::Vector{Int})
Renumber the colors in `color` using their index in the vector `sort(unique(color))`, so that they are forced to go from `1` to some `cmax` contiguously.
Return a tuple `(remapped_colors, color_to_ind)` such that `remapped_colors` is a vector containing the renumbered colors and `color_to_ind` is a dictionary giving the translation between old and new color numberings.
For all vertex indices `i` we have:
remapped_color[i] = color_to_ind[color[i]]
"""
function remap_colors(color::Vector{Int})
col_to_ind = Dict(c => i for (i, c) in enumerate(sort(unique(color))))
remapped_cols = [col_to_ind[c] for c in color]
return remapped_cols, col_to_ind
color_to_ind = Dict(c => i for (i, c) in enumerate(sort(unique(color))))
remapped_colors = [color_to_ind[c] for c in color]
return remapped_colors, color_to_ind
end

"""
Expand Down Expand Up @@ -595,8 +606,8 @@ struct BicoloringResult{
col_color_ind::Dict{Int,Int}
"row color to index"
row_color_ind::Dict{Int,Int}
"combination of `Br` and `Bc`"
B::Matrix{R}
"combination of `Br` and `Bc` (almost a concatenation up to color remapping)"
Br_and_Bc::Matrix{R}
"CSC storage of `A_and_noAᵀ - `colptr`"
large_colptr::Vector{Int}
"CSC storage of `A_and_noAᵀ - `rowval`"
Expand All @@ -621,7 +632,7 @@ function BicoloringResult(
row_color, row_color_ind = remap_colors(symmetric_color[(n + 1):(n + m)])
column_group = group_by_color(column_color)
row_group = group_by_color(row_color)
B = Matrix{R}(undef, n + m, maximum(column_colors(symmetric_result)))
Br_and_Bc = Matrix{R}(undef, n + m, maximum(column_colors(symmetric_result)))
large_colptr = copy(ag.S.colptr)
large_colptr[(n + 2):end] .= large_colptr[n + 1] # last few columns are empty
large_rowval = ag.S.rowval[1:(end ÷ 2)] # forget the second half of nonzeros
Expand All @@ -635,7 +646,7 @@ function BicoloringResult(
symmetric_result,
col_color_ind,
row_color_ind,
B,
Br_and_Bc,
large_colptr,
large_rowval,
)
Expand Down

0 comments on commit 637e5c9

Please sign in to comment.