Skip to content

Commit ec19388

Browse files
committed
Decompression of acyclic coloring with SparseMatrixCSC
1 parent 96830d4 commit ec19388

2 files changed

Lines changed: 156 additions & 4 deletions

File tree

src/decompression.jl

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,6 @@ end
468468

469469
## TreeSetColoringResult
470470

471-
# TODO: add method for A::SparseMatrixCSC
472-
473471
function decompress!(
474472
A::AbstractMatrix{R},
475473
B::AbstractMatrix{R},
@@ -513,6 +511,92 @@ function decompress!(
513511
return A
514512
end
515513

514+
function decompress!(
515+
A::SparseMatrixCSC{R},
516+
B::AbstractMatrix{R},
517+
result::TreeSetColoringResult,
518+
uplo::Symbol=:F,
519+
) where {R<:Real}
520+
@compat (;
521+
S,
522+
color,
523+
vertices_by_tree,
524+
reverse_bfs_orders,
525+
diagonal_indices,
526+
diagonal_nzind,
527+
lower_triangle_offsets,
528+
upper_triangle_offsets,
529+
buffer,
530+
) = result
531+
nzA = nonzeros(A)
532+
uplo == :F && check_same_pattern(A, S)
533+
534+
if eltype(buffer) == R
535+
buffer_right_type = buffer
536+
else
537+
buffer_right_type = similar(buffer, R)
538+
end
539+
540+
# Recover the diagonal coefficients of A
541+
if uplo == :L
542+
for i in diagonal_indices
543+
# A[i, i] is the first element in column i
544+
nzind = A.colptr[i]
545+
nzA[nzind] = B[i, color[i]]
546+
end
547+
elseif uplo == :U
548+
for i in diagonal_indices
549+
# A[i, i] is the last element in column i
550+
nzind = A.colptr[i + 1] - 1
551+
nzA[nzind] = B[i, color[i]]
552+
end
553+
else # uplo == :F
554+
for (k, i) in enumerate(diagonal_indices)
555+
nzind = diagonal_nzind[k]
556+
nzA[nzind] = B[i, color[i]]
557+
end
558+
end
559+
560+
# Index of offsets in lower_triangle_offsets and upper_triangle_offsets
561+
counter = 0
562+
563+
# Recover the off-diagonal coefficients of A
564+
for k in eachindex(vertices_by_tree, reverse_bfs_orders)
565+
for vertex in vertices_by_tree[k]
566+
buffer_right_type[vertex] = zero(R)
567+
end
568+
569+
for (i, j) in reverse_bfs_orders[k]
570+
counter += 1
571+
val = B[i, color[j]] - buffer_right_type[i]
572+
buffer_right_type[j] = buffer_right_type[j] + val
573+
574+
# A[i,j] = val
575+
if in_triangle(i, j, uplo)
576+
if uplo == :L
577+
nzind = A.colptr[j + 1] - lower_triangle_offsets[counter]
578+
else
579+
nzind = A.colptr[j] + upper_triangle_offsets[counter]
580+
end
581+
# Both values of `nzind` can be used if uplo = :F
582+
nzA[nzind] = val
583+
end
584+
585+
# A[j,i] = val
586+
if in_triangle(j, i, uplo)
587+
if uplo == :L
588+
nzind = A.colptr[i + 1] - lower_triangle_offsets[counter]
589+
else
590+
nzind = A.colptr[i] + upper_triangle_offsets[counter]
591+
end
592+
# Both values of `nzind` can be used if uplo = :F
593+
nzA[nzind] = val
594+
end
595+
end
596+
end
597+
return A
598+
end
599+
516600
## MatrixInverseColoringResult
517601

518602
function decompress!(

src/result.jl

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ struct TreeSetColoringResult{M,R} <:
227227
group::Vector{Vector{Int}}
228228
vertices_by_tree::Vector{Vector{Int}}
229229
reverse_bfs_orders::Vector{Vector{Tuple{Int,Int}}}
230+
diagonal_indices::Vector{Int}
231+
diagonal_nzind::Vector{Int}
232+
lower_triangle_offsets::Vector{Int}
233+
upper_triangle_offsets::Vector{Int}
230234
buffer::Vector{R}
231235
end
232236

@@ -236,6 +240,29 @@ function TreeSetColoringResult(
236240
nvertices = length(color)
237241
group = group_by_color(color)
238242

243+
# Vector for the decompression of the diagonal coefficients
244+
diagonal_indices = Int[]
245+
diagonal_nzind = Int[]
246+
ndiag = 0
247+
248+
n = size(S, 1)
249+
rv = rowvals(S)
250+
for j in axes(S, 2)
251+
for k in nzrange(S, j)
252+
i = rv[k]
253+
if i == j
254+
push!(diagonal_indices, i)
255+
push!(diagonal_nzind, k)
256+
ndiag += 1
257+
end
258+
end
259+
end
260+
261+
# Vectors for the decompression of the off-diagonal coefficients
262+
nedges = (nnz(S) - ndiag) ÷ 2
263+
lower_triangle_offsets = Vector{Int}(undef, nedges)
264+
upper_triangle_offsets = Vector{Int}(undef, nedges)
265+
239266
# forest is a structure DisjointSets from DataStructures.jl
240267
# - forest.intmap: a dictionary that maps an edge (i, j) to an integer k
241268
# - forest.revmap: a dictionary that does the reverse of intmap, mapping an integer k to an edge (i, j)
@@ -297,6 +324,9 @@ function TreeSetColoringResult(
297324
# Create a queue with a fixed size nvmax
298325
queue = Vector{Int}(undef, nvmax)
299326

327+
# Index in lower_triangle_offsets and upper_triangle_offsets
328+
index_offsets = 0
329+
300330
for k in 1:ntrees
301331
tree = trees[k]
302332

@@ -317,7 +347,7 @@ function TreeSetColoringResult(
317347
end
318348

319349
# continue until all leaves are treated
320-
while queue_start <= queue_end
350+
while queue_start queue_end
321351
leaf = queue[queue_start]
322352
queue_start += 1
323353

@@ -337,6 +367,35 @@ function TreeSetColoringResult(
337367
queue_end += 1
338368
queue[queue_end] = neighbor
339369
end
370+
371+
# Update lower_triangle_offsets and upper_triangle_offsets
372+
i = leaf
373+
j = neighbor
374+
col_i = view(rv, nzrange(S, i))
375+
col_j = view(rv, nzrange(S, j))
376+
index_ij = S.colptr[j] - 1 + searchsortedfirst(col_j, i) # S.nzval[index_ij] = S[i,j]
377+
@assert S.nzval[index_ij] == S[i,j]
378+
index_ji = S.colptr[i] - 1 + searchsortedfirst(col_i, j) # S.nzval[index_ji] = S[j,i]
379+
@assert S.nzval[index_ji] == S[j,i]
380+
index_offsets += 1
381+
382+
if in_triangle(i, j, :L)
383+
# uplo = :L or uplo = :F
384+
# A[i,j] is stored at index_ij = (A.colptr[j+1] - offset_L) in A.nzval
385+
lower_triangle_offsets[index_offsets] = S.colptr[j + 1] - index_ij
386+
387+
# uplo = :U or uplo = :F
388+
# A[j,i] is stored at index_ji = (A.colptr[i] + offset_U) in A.nzval
389+
upper_triangle_offsets[index_offsets] = index_ji - S.colptr[i]
390+
else
391+
# uplo = :L or uplo = :F
392+
# A[j,i] is stored at index_ji = (A.colptr[i+1] - offset_L) in A.nzval
393+
lower_triangle_offsets[index_offsets] = S.colptr[i + 1] - index_ji
394+
395+
# uplo = :U or uplo = :F
396+
# A[i,j] is stored at index_ij = (A.colptr[j] + offset_U) in A.nzval
397+
upper_triangle_offsets[index_offsets] = index_ij - S.colptr[j]
398+
end
340399
end
341400
end
342401
end
@@ -347,7 +406,16 @@ function TreeSetColoringResult(
347406
buffer = Vector{R}(undef, nvertices)
348407

349408
return TreeSetColoringResult(
350-
S, color, group, vertices_by_tree, reverse_bfs_orders, buffer
409+
S,
410+
color,
411+
group,
412+
vertices_by_tree,
413+
reverse_bfs_orders,
414+
diagonal_indices,
415+
diagonal_nzind,
416+
lower_triangle_offsets,
417+
upper_triangle_offsets,
418+
buffer,
351419
)
352420
end
353421

0 commit comments

Comments
 (0)