Skip to content

Commit 07bbbf8

Browse files
committed
[bicoloring] Use Br and Bc directly for the decompression
1 parent df101d7 commit 07bbbf8

5 files changed

Lines changed: 319 additions & 87 deletions

File tree

docs/src/dev.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SparseMatrixColorings.star_coloring
2727
SparseMatrixColorings.acyclic_coloring
2828
SparseMatrixColorings.group_by_color
2929
SparseMatrixColorings.Forest
30+
SparseMatrixColorings.remap_colors
3031
SparseMatrixColorings.StarSet
3132
SparseMatrixColorings.TreeSet
3233
```
@@ -39,8 +40,8 @@ SparseMatrixColorings.RowColoringResult
3940
SparseMatrixColorings.StarSetColoringResult
4041
SparseMatrixColorings.TreeSetColoringResult
4142
SparseMatrixColorings.LinearSystemColoringResult
42-
SparseMatrixColorings.BicoloringResult
43-
SparseMatrixColorings.remap_colors
43+
SparseMatrixColorings.StarSetBicoloringResult
44+
SparseMatrixColorings.TreeSetBicoloringResult
4445
```
4546

4647
## Testing

src/decompression.jl

Lines changed: 149 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,6 @@ function decompress!(
520520
(; ag, color, reverse_bfs_orders, tree_edge_indices, nt, buffer) = result
521521
(; S) = ag
522522
uplo == :F && check_same_pattern(A, S)
523-
R = eltype(A)
524523
fill!(A, zero(R))
525524

526525
if eltype(buffer) == R
@@ -714,61 +713,167 @@ function decompress!(
714713
return A
715714
end
716715

717-
## BicoloringResult
718-
719-
function _join_compressed!(result::BicoloringResult, Br::AbstractMatrix, Bc::AbstractMatrix)
720-
#=
721-
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)]`.
722-
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)]`.
723-
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`.
724-
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`).
725-
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.
726-
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.
727-
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.
728-
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.
729-
We use the vectors `symmetric_to_row` and `symmetric_to_column` to map from symmetric colors to row and column colors.
730-
=#
731-
(; A, symmetric_to_column, symmetric_to_row) = result
716+
## StarSetBicoloringResult
717+
718+
function decompress!(
719+
A::AbstractMatrix,
720+
Br::AbstractMatrix,
721+
Bc::AbstractMatrix,
722+
result::StarSetBicoloringResult,
723+
)
724+
(; ag, symmetric_color, symmetric_to_row, symmetric_to_column, star_set) = result
725+
(; star, hub, spokes) = star_set
726+
(; S) = ag
727+
fill!(A, zero(eltype(A)))
728+
732729
m, n = size(A)
733-
R = Base.promote_eltype(Br, Bc)
734-
if eltype(result.Br_and_Bc) == R
735-
Br_and_Bc = result.Br_and_Bc
736-
else
737-
Br_and_Bc = similar(result.Br_and_Bc, R)
738-
end
739-
fill!(Br_and_Bc, zero(R))
740-
for c in axes(Br_and_Bc, 2)
741-
if symmetric_to_row[c] > 0 # some rows were colored with the symmetric color c
742-
copyto!(view(Br_and_Bc, 1:n, c), view(Br, symmetric_to_row[c], :))
743-
end
744-
if symmetric_to_column[c] > 0 # some columns were colored with the symmetric color c
745-
copyto!(
746-
view(Br_and_Bc, (n + 1):(n + m), c), view(Bc, :, symmetric_to_column[c])
747-
)
730+
for s in eachindex(hub, spokes)
731+
j = abs(hub[s])
732+
cj = symmetric_color[j]
733+
for i in spokes[s]
734+
if in_triangle(i, j, :L)
735+
A[i - n, j] = Bc[i - n, symmetric_to_column[cj]]
736+
else
737+
A[j - n, i] = Br[symmetric_to_row[cj], i]
738+
end
748739
end
749740
end
750-
return Br_and_Bc
741+
return A
751742
end
752743

753744
function decompress!(
754-
A::AbstractMatrix, Br::AbstractMatrix, Bc::AbstractMatrix, result::BicoloringResult
745+
A::SparseMatrixCSC,
746+
Br::AbstractMatrix,
747+
Bc::AbstractMatrix,
748+
result::StarSetBicoloringResult,
755749
)
750+
(; ag, A_indices, compressed_indices, pos_Br) = result
751+
(; S) = ag
752+
nzA = nonzeros(A)
753+
for k in 1:pos_Br
754+
nzA[A_indices[k]] = Br[compressed_indices[k]]
755+
end
756+
for k in (pos_Br + 1):length(nzA)
757+
nzA[A_indices[k]] = Bc[compressed_indices[k]]
758+
end
759+
return A
760+
end
761+
762+
## TreeSetBicoloringResult
763+
764+
function decompress!(
765+
A::AbstractMatrix{R},
766+
Br::AbstractMatrix{R},
767+
Bc::AbstractMatrix{R},
768+
result::TreeSetBicoloringResult,
769+
) where {R<:Real}
770+
(;
771+
ag,
772+
symmetric_color,
773+
symmetric_to_row,
774+
symmetric_to_column,
775+
reverse_bfs_orders,
776+
buffer,
777+
) = result
778+
(; S) = ag
779+
756780
m, n = size(A)
757-
Br_and_Bc = _join_compressed!(result, Br, Bc)
758-
A_and_Aᵀ = decompress(Br_and_Bc, result.symmetric_result)
759-
copyto!(A, A_and_Aᵀ[(n + 1):(n + m), 1:n]) # original matrix in bottom left corner
781+
fill!(A, zero(R))
782+
783+
if eltype(buffer) == R
784+
buffer_right_type = buffer
785+
else
786+
buffer_right_type = similar(buffer, R)
787+
end
788+
789+
for k in eachindex(reverse_bfs_orders)
790+
# Reset the buffer to zero for all vertices in a tree (except the root)
791+
for (vertex, _) in reverse_bfs_orders[k]
792+
buffer_right_type[vertex] = zero(R)
793+
end
794+
# Reset the buffer to zero for the root vertex
795+
(_, root) = reverse_bfs_orders[k][end]
796+
buffer_right_type[root] = zero(R)
797+
798+
for (i, j) in reverse_bfs_orders[k]
799+
cj = symmetric_color[j]
800+
if in_triangle(i, j, :L)
801+
val = Bc[i - n, symmetric_to_column[cj]] - buffer_right_type[i]
802+
buffer_right_type[j] = buffer_right_type[j] + val
803+
A[i - n, j] = val
804+
else
805+
val = Br[symmetric_to_row[cj], i] - buffer_right_type[i]
806+
buffer_right_type[j] = buffer_right_type[j] + val
807+
A[j - n, i] = val
808+
end
809+
end
810+
end
760811
return A
761812
end
762813

763814
function decompress!(
764-
A::SparseMatrixCSC, Br::AbstractMatrix, Bc::AbstractMatrix, result::BicoloringResult
765-
)
766-
(; large_colptr, large_rowval, symmetric_result) = result
815+
A::SparseMatrixCSC{R},
816+
Br::AbstractMatrix{R},
817+
Bc::AbstractMatrix{R},
818+
result::TreeSetBicoloringResult,
819+
) where {R<:Real}
820+
(;
821+
ag,
822+
symmetric_color,
823+
symmetric_to_column,
824+
symmetric_to_row,
825+
reverse_bfs_orders,
826+
A_indices,
827+
buffer,
828+
) = result
829+
(; S) = ag
830+
767831
m, n = size(A)
768-
Br_and_Bc = _join_compressed!(result, Br, Bc)
769-
# pretend A is larger
770-
A_and_noAᵀ = SparseMatrixCSC(m + n, m + n, large_colptr, large_rowval, A.nzval)
771-
# decompress lower triangle only
772-
decompress!(A_and_noAᵀ, Br_and_Bc, symmetric_result, :L)
832+
A_colptr = A.colptr
833+
nzA = nonzeros(A)
834+
835+
if eltype(buffer) == R
836+
buffer_right_type = buffer
837+
else
838+
buffer_right_type = similar(buffer, R)
839+
end
840+
841+
# Recover the coefficients of A
842+
counter = 0
843+
for k in eachindex(reverse_bfs_orders)
844+
# Reset the buffer to zero for all vertices in a tree (except the root)
845+
for (vertex, _) in reverse_bfs_orders[k]
846+
buffer_right_type[vertex] = zero(R)
847+
end
848+
# Reset the buffer to zero for the root vertex
849+
(_, root) = reverse_bfs_orders[k][end]
850+
buffer_right_type[root] = zero(R)
851+
852+
for (i, j) in reverse_bfs_orders[k]
853+
counter += 1
854+
cj = symmetric_color[j]
855+
856+
#! format: off
857+
# A[i,j] is in the lower triangular part of A
858+
if in_triangle(i, j, :L)
859+
val = Bc[i - n, symmetric_to_column[cj]] - buffer_right_type[i]
860+
buffer_right_type[j] = buffer_right_type[j] + val
861+
862+
# A[i,j] is stored at index_ij = A_indices[counter] in A.nzval
863+
nzind = A_indices[counter]
864+
nzA[nzind] = val
865+
866+
# A[i,j] is in the upper triangular part of A
867+
else
868+
val = Br[symmetric_to_row[cj], i] - buffer_right_type[i]
869+
buffer_right_type[j] = buffer_right_type[j] + val
870+
871+
# A[j,i] is stored at index_ji = A_indices[counter] in A.nzval
872+
nzind = A_indices[counter]
873+
nzA[nzind] = val
874+
end
875+
#! format: on
876+
end
877+
end
773878
return A
774879
end

src/interface.jl

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -296,19 +296,16 @@ function _coloring(
296296
A::AbstractMatrix,
297297
::ColoringProblem{:nonsymmetric,:bidirectional},
298298
algo::GreedyColoringAlgorithm{:direct},
299-
decompression_eltype::Type{R},
299+
decompression_eltype::Type,
300300
symmetric_pattern::Bool,
301-
) where {R}
301+
)
302302
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
303303
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
304304
color, star_set = star_coloring(ag, algo.order, algo.postprocessing)
305305
if speed_setting isa WithResult
306-
symmetric_result = StarSetColoringResult(A_and_Aᵀ, ag, color, star_set)
307-
return BicoloringResult(A, ag, symmetric_result, R)
306+
return StarSetBicoloringResult(A, ag, symmetric_color, star_set)
308307
else
309-
row_color, column_color, _ = remap_colors(
310-
eltype(ag), color, maximum(color), size(A)...
311-
)
308+
row_color, column_color, _ = remap_colors(eltype(ag), color, maximum(color), size(A)...)
312309
return row_color, column_color
313310
end
314311
end
@@ -325,12 +322,9 @@ function _coloring(
325322
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
326323
color, tree_set = acyclic_coloring(ag, algo.order, algo.postprocessing)
327324
if speed_setting isa WithResult
328-
symmetric_result = TreeSetColoringResult(A_and_Aᵀ, ag, color, tree_set, R)
329-
return BicoloringResult(A, ag, symmetric_result, R)
325+
return TreeSetBicoloringResult(A, ag, symmetric_color, tree_set, R)
330326
else
331-
row_color, column_color, _ = remap_colors(
332-
eltype(ag), color, maximum(color), size(A)...
333-
)
327+
row_color, column_color, _ = remap_colors(eltype(ag), color, maximum(color), size(A)...)
334328
return row_color, column_color
335329
end
336330
end

0 commit comments

Comments
 (0)