Skip to content

Commit 3f7078d

Browse files
committed
[bicoloring] Use Br and Bc directly for the decompression
1 parent d9ec840 commit 3f7078d

File tree

7 files changed

+376
-103
lines changed

7 files changed

+376
-103
lines changed

docs/src/dev.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ SparseMatrixColorings.partial_distance2_coloring
2626
SparseMatrixColorings.star_coloring
2727
SparseMatrixColorings.acyclic_coloring
2828
SparseMatrixColorings.group_by_color
29+
SparseMatrixColorings.remap_colors
2930
SparseMatrixColorings.Forest
3031
SparseMatrixColorings.StarSet
3132
SparseMatrixColorings.TreeSet
@@ -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: 171 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -515,12 +515,14 @@ end
515515
## TreeSetColoringResult
516516

517517
function decompress!(
518-
A::AbstractMatrix, B::AbstractMatrix, result::TreeSetColoringResult, uplo::Symbol=:F
519-
)
518+
A::AbstractMatrix{R},
519+
B::AbstractMatrix{R},
520+
result::TreeSetColoringResult,
521+
uplo::Symbol=:F,
522+
) where {R<:Real}
520523
(; ag, color, reverse_bfs_orders, tree_edge_indices, nt, buffer) = result
521524
(; S) = ag
522525
uplo == :F && check_same_pattern(A, S)
523-
R = eltype(A)
524526
fill!(A, zero(R))
525527

526528
if eltype(buffer) == R
@@ -714,61 +716,182 @@ function decompress!(
714716
return A
715717
end
716718

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
732-
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)
719+
## StarSetBicoloringResult
720+
721+
# function decompress!(
722+
# A::AbstractMatrix,
723+
# Br::AbstractMatrix,
724+
# Bc::AbstractMatrix,
725+
# result::StarSetBicoloringResult,
726+
# )
727+
# (; ag, S, A_indices, compressed_indices, pos_Bc) = result
728+
# fill!(A, zero(eltype(A)))
729+
730+
# ind_Br = 0
731+
# ind_Bc = pos_Br
732+
# counter = 0
733+
# rvS = rowvals(S)
734+
# for j in axes(S, 2)
735+
# for k in nzrange(S, j)
736+
# i = rvS[k]
737+
# counter += 1
738+
# ...
739+
# if in_triangle(i, j, :L)
740+
# ind_Br += 1
741+
# A[i - n, j] = Br[compressed_indices[ind_Br]]
742+
# else
743+
# ind_Bc += 1
744+
# A[j - n, i] = Bc[compressed_indices[ind_Bc]]
745+
# end
746+
# end
747+
# end
748+
# return A
749+
# end
750+
751+
function decompress!(
752+
A::SparseMatrixCSC,
753+
Br::AbstractMatrix,
754+
Bc::AbstractMatrix,
755+
result::StarSetBicoloringResult,
756+
)
757+
(; ag, A_indices, compressed_indices, pos_Bc) = result
758+
nzA = nonzeros(A)
759+
for k in 1:pos_Bc
760+
nzA[A_indices[k]] = Bc[compressed_indices[k]]
738761
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-
)
748-
end
762+
for k in (pos_Bc + 1):length(nzA)
763+
nzA[A_indices[k]] = Br[compressed_indices[k]]
749764
end
750-
return Br_and_Bc
765+
return A
751766
end
752767

768+
## TreeSetBicoloringResult
769+
753770
function decompress!(
754-
A::AbstractMatrix, Br::AbstractMatrix, Bc::AbstractMatrix, result::BicoloringResult
755-
)
771+
A::AbstractMatrix{R},
772+
Br::AbstractMatrix{R},
773+
Bc::AbstractMatrix{R},
774+
result::TreeSetBicoloringResult,
775+
) where {R<:Real}
776+
(;
777+
ag,
778+
symmetric_color,
779+
symmetric_to_row,
780+
symmetric_to_column,
781+
reverse_bfs_orders,
782+
buffer,
783+
) = result
784+
(; S) = ag
785+
756786
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
787+
fill!(A, zero(R))
788+
789+
if eltype(buffer) == R
790+
buffer_right_type = buffer
791+
else
792+
buffer_right_type = similar(buffer, R)
793+
end
794+
795+
for k in 1:nt
796+
# Positions of the first and last edges of the tree
797+
first = tree_edge_indices[k]
798+
last = tree_edge_indices[k + 1] - 1
799+
800+
# Reset the buffer to zero for all vertices in the tree (except the root)
801+
for pos in first:last
802+
buffer_right_type[vertex] = zero(R)
803+
end
804+
# Reset the buffer to zero for the root vertex
805+
(_, root) = reverse_bfs_orders[last]
806+
buffer_right_type[root] = zero(R)
807+
808+
for pos in first:last
809+
(i, j) = reverse_bfs_orders[pos]
810+
cj = symmetric_color[j]
811+
if in_triangle(i, j, :L)
812+
val = Bc[i - n, symmetric_to_column[cj]] - buffer_right_type[i]
813+
buffer_right_type[j] = buffer_right_type[j] + val
814+
A[i - n, j] = val
815+
else
816+
val = Br[symmetric_to_row[cj], i] - buffer_right_type[i]
817+
buffer_right_type[j] = buffer_right_type[j] + val
818+
A[j - n, i] = val
819+
end
820+
end
821+
end
760822
return A
761823
end
762824

763825
function decompress!(
764-
A::SparseMatrixCSC, Br::AbstractMatrix, Bc::AbstractMatrix, result::BicoloringResult
765-
)
766-
(; large_colptr, large_rowval, symmetric_result) = result
826+
A::SparseMatrixCSC{R},
827+
Br::AbstractMatrix{R},
828+
Bc::AbstractMatrix{R},
829+
result::TreeSetBicoloringResult,
830+
) where {R<:Real}
831+
(;
832+
ag,
833+
symmetric_color,
834+
symmetric_to_column,
835+
symmetric_to_row,
836+
reverse_bfs_orders,
837+
A_indices,
838+
buffer,
839+
) = result
840+
(; S) = ag
841+
767842
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)
843+
A_colptr = A.colptr
844+
nzA = nonzeros(A)
845+
846+
if eltype(buffer) == R
847+
buffer_right_type = buffer
848+
else
849+
buffer_right_type = similar(buffer, R)
850+
end
851+
852+
# Recover the coefficients of A
853+
counter = 0
854+
855+
# Recover the off-diagonal coefficients of A
856+
for k in 1:nt
857+
# Positions of the first and last edges of the tree
858+
first = tree_edge_indices[k]
859+
last = tree_edge_indices[k + 1] - 1
860+
861+
# Reset the buffer to zero for all vertices in the tree (except the root)
862+
for pos in first:last
863+
buffer_right_type[vertex] = zero(R)
864+
end
865+
# Reset the buffer to zero for the root vertex
866+
(_, root) = reverse_bfs_orders[last]
867+
buffer_right_type[root] = zero(R)
868+
869+
for pos in first:last
870+
(i, j) = reverse_bfs_orders[pos]
871+
counter += 1
872+
cj = symmetric_color[j]
873+
874+
#! format: off
875+
# A[i,j] is in the lower triangular part of A
876+
if in_triangle(i, j, :L)
877+
val = Bc[i - n, symmetric_to_column[cj]] - buffer_right_type[i]
878+
buffer_right_type[j] = buffer_right_type[j] + val
879+
880+
# A[i,j] is stored at index_ij = A_indices[counter] in A.nzval
881+
nzind = A_indices[counter]
882+
nzA[nzind] = val
883+
884+
# A[i,j] is in the upper triangular part of A
885+
else
886+
val = Br[symmetric_to_row[cj], i] - buffer_right_type[i]
887+
buffer_right_type[j] = buffer_right_type[j] + val
888+
889+
# A[j,i] is stored at index_ji = A_indices[counter] in A.nzval
890+
nzind = A_indices[counter]
891+
nzA[nzind] = val
892+
end
893+
#! format: on
894+
end
895+
end
773896
return A
774897
end

src/graph.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ end
100100
Return a [`SparsityPatternCSC`](@ref) corresponding to the matrix `[0 Aᵀ; A 0]`, with a minimum of allocations.
101101
"""
102102
function bidirectional_pattern(A::AbstractMatrix; symmetric_pattern::Bool)
103-
bidirectional_pattern(SparsityPatternCSC(SparseMatrixCSC(A)); symmetric_pattern)
103+
S = SparsityPatternCSC(SparseMatrixCSC(A))
104+
bidirectional_pattern(S; symmetric_pattern)
104105
end
105106

106107
function bidirectional_pattern(S::SparsityPatternCSC{T}; symmetric_pattern::Bool) where {T}
@@ -172,7 +173,7 @@ function bidirectional_pattern(S::SparsityPatternCSC{T}; symmetric_pattern::Bool
172173

173174
# Create the SparsityPatternCSC of the augmented adjacency matrix
174175
S_and_Sᵀ = SparsityPatternCSC{T}(p, p, colptr, rowval)
175-
return S_and_Sᵀ, edge_to_index
176+
return S, S_and_Sᵀ, edge_to_index
176177
end
177178

178179
function build_edge_to_index(S::SparsityPatternCSC{T}) where {T}

src/interface.jl

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ function _coloring(
282282
algo::GreedyColoringAlgorithm{:substitution},
283283
decompression_eltype::Type{R},
284284
symmetric_pattern::Bool,
285-
) where {R}
285+
) where {R<:Real}
286286
ag = AdjacencyGraph(A; has_diagonal=true)
287287
vertices_in_order = vertices(ag, algo.order)
288288
color, tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
@@ -298,19 +298,18 @@ function _coloring(
298298
A::AbstractMatrix,
299299
::ColoringProblem{:nonsymmetric,:bidirectional},
300300
algo::GreedyColoringAlgorithm{:direct},
301-
decompression_eltype::Type{R},
301+
decompression_eltype::Type,
302302
symmetric_pattern::Bool,
303303
) where {R}
304-
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
305-
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
304+
S, S_and_Sᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
305+
ag = AdjacencyGraph(S_and_Sᵀ, edge_to_index; has_diagonal=false)
306306
vertices_in_order = vertices(ag, algo.order)
307307
color, star_set = star_coloring(ag, vertices_in_order, algo.postprocessing)
308308
if speed_setting isa WithResult
309-
symmetric_result = StarSetColoringResult(A_and_Aᵀ, ag, color, star_set)
310-
return BicoloringResult(A, ag, symmetric_result, R)
309+
return StarSetBicoloringResult(A, S, ag, symmetric_color, star_set)
311310
else
312311
row_color, column_color, _ = remap_colors(
313-
eltype(ag), color, maximum(color), size(A)...
312+
eltype(ag), symmetric_color, maximum(symmetric_color), size(A)...
314313
)
315314
return row_color, column_color
316315
end
@@ -324,16 +323,15 @@ function _coloring(
324323
decompression_eltype::Type{R},
325324
symmetric_pattern::Bool,
326325
) where {R}
327-
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
328-
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
326+
S, S_and_Sᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
327+
ag = AdjacencyGraph(S_and_Sᵀ, edge_to_index; has_diagonal=false)
329328
vertices_in_order = vertices(ag, algo.order)
330329
color, tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
331330
if speed_setting isa WithResult
332-
symmetric_result = TreeSetColoringResult(A_and_Aᵀ, ag, color, tree_set, R)
333-
return BicoloringResult(A, ag, symmetric_result, R)
331+
return TreeSetBicoloringResult(A, S, ag, symmetric_color, tree_set, R)
334332
else
335333
row_color, column_color, _ = remap_colors(
336-
eltype(ag), color, maximum(color), size(A)...
334+
eltype(ag), symmetric_color, maximum(symmetric_color), size(A)...
337335
)
338336
return row_color, column_color
339337
end

0 commit comments

Comments
 (0)