Skip to content

Commit 398490d

Browse files
authored
Optimize remap_colors (#197)
* Avoid the call to remap_colors in postprocess! * Optimize remap_colors * Apply suggestions from code review * Update src/coloring.jl * Update coloring.jl
1 parent b494188 commit 398490d

File tree

3 files changed

+84
-31
lines changed

3 files changed

+84
-31
lines changed

src/coloring.jl

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ function star_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessing::
123123
end
124124
star_set = StarSet(star, hub, nb_spokes)
125125
if postprocessing
126-
postprocess!(color, star_set, g)
126+
# Reuse the vector forbidden_colors to compute offsets during post-processing
127+
postprocess!(color, star_set, g, forbidden_colors)
127128
end
128129
return color, star_set
129130
end
@@ -351,7 +352,8 @@ function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessin
351352
end
352353
tree_set = TreeSet(forest, nb_vertices(g))
353354
if postprocessing
354-
postprocess!(color, tree_set, g)
355+
# Reuse the vector forbidden_colors to compute offsets during post-processing
356+
postprocess!(color, tree_set, g, forbidden_colors)
355357
end
356358
return color, tree_set
357359
end
@@ -551,6 +553,7 @@ function postprocess!(
551553
color::AbstractVector{<:Integer},
552554
star_or_tree_set::Union{StarSet,TreeSet},
553555
g::AdjacencyGraph,
556+
offsets::Vector{Int},
554557
)
555558
(; S) = g
556559
# flag which colors are actually used during decompression
@@ -642,15 +645,28 @@ function postprocess!(
642645

643646
# if at least one of the colors is useless, modify the color assignments of vertices
644647
if any(!, color_used)
645-
# assign the neutral color to every vertex with a useless color
648+
num_colors_useless = 0
649+
650+
# determine what are the useless colors and compute the offsets
651+
for ci in 1:nb_colors
652+
if color_used[ci]
653+
offsets[ci] = num_colors_useless
654+
else
655+
num_colors_useless += 1
656+
end
657+
end
658+
659+
# assign the neutral color to every vertex with a useless color and remap the colors
646660
for i in eachindex(color)
647661
ci = color[i]
648662
if !color_used[ci]
663+
# assign the neutral color
649664
color[i] = 0
665+
else
666+
# remap the color to not have any gap
667+
color[i] -= offsets[ci]
650668
end
651669
end
652-
# remap colors to decrease the highest one by filling gaps
653-
color .= remap_colors(color)[1]
654670
end
655671
return color
656672
end

src/decompression.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -711,9 +711,9 @@ function _join_compressed!(result::BicoloringResult, Br::AbstractMatrix, Bc::Abs
711711
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.
712712
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.
713713
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.
714-
We use the dictionaries `col_color_ind` and `row_color_ind` to map from symmetric colors to row/column colors.
714+
We use the vectors `symmetric_to_row` and `symmetric_to_column` to map from symmetric colors to row and column colors.
715715
=#
716-
(; A, col_color_ind, row_color_ind) = result
716+
(; A, symmetric_to_column, symmetric_to_row) = result
717717
m, n = size(A)
718718
R = Base.promote_eltype(Br, Bc)
719719
if eltype(result.Br_and_Bc) == R
@@ -723,11 +723,13 @@ function _join_compressed!(result::BicoloringResult, Br::AbstractMatrix, Bc::Abs
723723
end
724724
fill!(Br_and_Bc, zero(R))
725725
for c in axes(Br_and_Bc, 2)
726-
if haskey(row_color_ind, c) # some rows were colored with symmetric color c
727-
copyto!(view(Br_and_Bc, 1:n, c), view(Br, row_color_ind[c], :))
726+
if symmetric_to_row[c] > 0 # some rows were colored with the symmetric color c
727+
copyto!(view(Br_and_Bc, 1:n, c), view(Br, symmetric_to_row[c], :))
728728
end
729-
if haskey(col_color_ind, c) # some columns were colored with symmetric c
730-
copyto!(view(Br_and_Bc, (n + 1):(n + m), c), view(Bc, :, col_color_ind[c]))
729+
if symmetric_to_column[c] > 0 # some columns were colored with the symmetric color c
730+
copyto!(
731+
view(Br_and_Bc, (n + 1):(n + m), c), view(Bc, :, symmetric_to_column[c])
732+
)
731733
end
732734
end
733735
return Br_and_Bc

src/result.jl

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -456,22 +456,55 @@ end
456456
## Bicoloring result
457457

458458
"""
459-
remap_colors(color::Vector{Int})
459+
remap_colors(color::Vector{Int}, num_sym_colors::Int, m::Int, n::Int)
460460
461-
Renumber the colors in `color` using their index in the vector `sort(unique(color))`, so that the non-zero colors are forced to go from `1` to some `cmax` contiguously.
461+
Return a tuple `(row_color, column_color, symmetric_to_row, symmetric_to_column)` such that `row_color` and `column_color` are vectors containing the renumbered colors for rows and columns.
462+
`symmetric_to_row` and `symmetric_to_column` are vectors that map symmetric colors to row and column colors.
462463
463-
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.
464+
For all vertex indices `i` between `1` and `m` we have:
464465
465-
For all vertex indices `i` we have:
466+
row_color[i] = symmetric_to_row[color[n+i]]
466467
467-
remapped_color[i] = color_to_ind[color[i]]
468+
For all vertex indices `j` between `1` and `n` we have:
469+
470+
column_color[j] = symmetric_to_column[color[j]]
468471
"""
469-
function remap_colors(color::Vector{Int})
470-
sorted_colors = sort!(unique(color))
471-
offset = sorted_colors[1] == 0 ? 1 : 0
472-
color_to_ind = Dict(c => i - offset for (i, c) in enumerate(sorted_colors))
473-
remapped_colors = [color_to_ind[c] for c in color]
474-
return remapped_colors, color_to_ind
472+
function remap_colors(color::Vector{Int}, num_sym_colors::Int, m::Int, n::Int)
473+
# Map symmetric colors to column colors
474+
symmetric_to_column = zeros(Int, num_sym_colors)
475+
column_color = zeros(Int, n)
476+
477+
counter = 0
478+
for j in 1:n
479+
cj = color[j]
480+
if cj > 0
481+
# First time that we encounter this column color
482+
if symmetric_to_column[cj] == 0
483+
counter += 1
484+
symmetric_to_column[cj] = counter
485+
end
486+
column_color[j] = symmetric_to_column[cj]
487+
end
488+
end
489+
490+
# Map symmetric colors to row colors
491+
symmetric_to_row = zeros(Int, num_sym_colors)
492+
row_color = zeros(Int, m)
493+
494+
counter = 0
495+
for i in (n + 1):(n + m)
496+
ci = color[i]
497+
if ci > 0
498+
# First time that we encounter this row color
499+
if symmetric_to_row[ci] == 0
500+
counter += 1
501+
symmetric_to_row[ci] = counter
502+
end
503+
row_color[i - n] = symmetric_to_row[ci]
504+
end
505+
end
506+
507+
return row_color, column_color, symmetric_to_row, symmetric_to_column
475508
end
476509

477510
"""
@@ -509,10 +542,10 @@ struct BicoloringResult{
509542
row_group::V
510543
"result for the coloring of the symmetric 2 x 2 block matrix"
511544
symmetric_result::SR
512-
"column color to index"
513-
col_color_ind::Dict{Int,Int}
514-
"row color to index"
515-
row_color_ind::Dict{Int,Int}
545+
"maps symmetric colors to column colors"
546+
symmetric_to_column::Vector{Int}
547+
"maps symmetric colors to row colors"
548+
symmetric_to_row::Vector{Int}
516549
"combination of `Br` and `Bc` (almost a concatenation up to color remapping)"
517550
Br_and_Bc::Matrix{R}
518551
"CSC storage of `A_and_noAᵀ - `colptr`"
@@ -535,11 +568,13 @@ function BicoloringResult(
535568
) where {R}
536569
m, n = size(A)
537570
symmetric_color = column_colors(symmetric_result)
538-
column_color, col_color_ind = remap_colors(symmetric_color[1:n])
539-
row_color, row_color_ind = remap_colors(symmetric_color[(n + 1):(n + m)])
571+
num_sym_colors = maximum(symmetric_color)
572+
row_color, column_color, symmetric_to_row, symmetric_to_column = remap_colors(
573+
symmetric_color, num_sym_colors, m, n
574+
)
540575
column_group = group_by_color(column_color)
541576
row_group = group_by_color(row_color)
542-
Br_and_Bc = Matrix{R}(undef, n + m, maximum(column_colors(symmetric_result)))
577+
Br_and_Bc = Matrix{R}(undef, n + m, num_sym_colors)
543578
large_colptr = copy(ag.S.colptr)
544579
large_colptr[(n + 2):end] .= large_colptr[n + 1] # last few columns are empty
545580
large_rowval = ag.S.rowval[1:(end ÷ 2)] # forget the second half of nonzeros
@@ -551,8 +586,8 @@ function BicoloringResult(
551586
column_group,
552587
row_group,
553588
symmetric_result,
554-
col_color_ind,
555-
row_color_ind,
589+
symmetric_to_column,
590+
symmetric_to_row,
556591
Br_and_Bc,
557592
large_colptr,
558593
large_rowval,

0 commit comments

Comments
 (0)