Skip to content

Commit 750be07

Browse files
amontoisongdalle
andauthored
Optimize star coloring and its postprocessing (#171)
* Optimize star coloring and its postprocessing * Better handle trivial stars in the postprocessing * Use JuliaFormatter for coloring.jl * Remove utils.jl from this PR * Fix an error in postprocess! * Switch hub when necessary --------- Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>
1 parent 7149c41 commit 750be07

2 files changed

Lines changed: 60 additions & 16 deletions

File tree

src/coloring.jl

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,15 @@ If `postprocessing=true`, some colors might be replaced with `0` (the "neutral"
7979
function star_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessing::Bool)
8080
# Initialize data structures
8181
nv = nb_vertices(g)
82+
ne = nb_edges(g)
8283
color = zeros(Int, nv)
8384
forbidden_colors = zeros(Int, nv)
8485
first_neighbor = fill((0, 0), nv) # at first no neighbors have been encountered
8586
treated = zeros(Int, nv)
8687
star = Dict{Tuple{Int,Int},Int}()
88+
sizehint!(star, ne)
8789
hub = Int[] # one hub for each star, including the trivial ones
90+
nb_spokes = Int[] # number of spokes for each star
8891
vertices_in_order = vertices(g, order)
8992

9093
for v in vertices_in_order
@@ -116,10 +119,9 @@ function star_coloring(g::AdjacencyGraph, order::AbstractOrder; postprocessing::
116119
break
117120
end
118121
end
119-
_update_stars!(star, hub, g, v, color, first_neighbor)
122+
_update_stars!(star, hub, nb_spokes, g, v, color, first_neighbor)
120123
end
121-
hub .= abs.(hub) # make all hubs actual (positive) hubs before creating StarSet
122-
star_set = StarSet(star, hub)
124+
star_set = StarSet(star, hub, nb_spokes)
123125
if postprocessing
124126
postprocess!(color, star_set, g)
125127
end
@@ -138,20 +140,29 @@ $TYPEDFIELDS
138140
struct StarSet
139141
"a mapping from edges (pair of vertices) to their star index"
140142
star::Dict{Tuple{Int,Int},Int}
141-
"a mapping from star indices to their hub (hubs of single-edge stars are picked arbitrarily)"
143+
"a mapping from star indices to their hub (undefined hubs for single-edge stars are the negative value of one of the vertices, picked arbitrarily)"
142144
hub::Vector{Int}
143145
"a mapping from star indices to the vector of their spokes"
144146
spokes::Vector{Vector{Int}}
145147
end
146148

147-
function StarSet(star, hub)
148-
spokes = [Int[] for s in eachindex(hub)]
149+
function StarSet(star::Dict{Tuple{Int,Int},Int}, hub::Vector{Int}, nb_spokes::Vector{Int})
150+
# Create a list of spokes for each star, preallocating their sizes based on nb_spokes
151+
spokes = [Vector{Int}(undef, ns) for ns in nb_spokes]
152+
153+
# Reuse nb_spokes as counters to track the current index while filling the spokes
154+
fill!(nb_spokes, 0)
155+
149156
for ((i, j), s) in pairs(star)
150-
h = hub[s]
157+
h = abs(hub[s])
158+
nb_spokes[s] += 1
159+
index = nb_spokes[s]
160+
161+
# Assign the non-hub vertex (spoke) to the correct position in spokes
151162
if i == h
152-
push!(spokes[s], j)
163+
spokes[s][index] = j
153164
elseif j == h
154-
push!(spokes[s], i)
165+
spokes[s][index] = i
155166
end
156167
end
157168
return StarSet(star, hub, spokes)
@@ -181,6 +192,7 @@ function _update_stars!(
181192
# modified
182193
star::Dict{<:Tuple,<:Integer},
183194
hub::AbstractVector{<:Integer},
195+
nb_spokes::AbstractVector{<:Integer},
184196
# not modified
185197
g::AdjacencyGraph,
186198
v::Integer,
@@ -194,8 +206,10 @@ function _update_stars!(
194206
for x in neighbors(g, w)
195207
if x != v && color[x] == color[v] # vw, wx ∈ E
196208
wx = _sort(w, x)
197-
hub[star[wx]] = w # this may already be true
198-
star[vw] = star[wx]
209+
star_wx = star[wx]
210+
hub[star_wx] = w # this may already be true
211+
nb_spokes[star_wx] += 1
212+
star[vw] = star_wx
199213
x_exists = true
200214
break
201215
end
@@ -204,10 +218,13 @@ function _update_stars!(
204218
(p, q) = first_neighbor[color[w]]
205219
if p == v && q != w # vw, vq ∈ E and color[w] = color[q]
206220
vq = _sort(v, q)
207-
hub[star[vq]] = v # this may already be true
208-
star[vw] = star[vq]
221+
star_vq = star[vq]
222+
hub[star_vq] = v # this may already be true
223+
nb_spokes[star_vq] += 1
224+
star[vw] = star_vq
209225
else # vw forms a new star
210226
push!(hub, -max(v, w)) # star is trivial (composed only of two vertices) so we set the hub to a negative value, but it allows us to choose one of the two vertices
227+
push!(nb_spokes, 1)
211228
star[vw] = length(hub)
212229
end
213230
end
@@ -543,10 +560,37 @@ function postprocess!(
543560
end
544561
if star_or_tree_set isa StarSet
545562
# only the colors of the hubs are used
546-
(; hub) = star_or_tree_set
563+
(; hub, spokes) = star_or_tree_set
564+
nb_trivial_star = 0
565+
566+
# Iterate through all non-trivial stars
547567
for s in eachindex(hub)
548568
j = hub[s]
549-
color_used[color[j]] = true
569+
if j > 0
570+
color_used[color[j]] = true
571+
else
572+
nb_trivial_star += 1
573+
end
574+
end
575+
576+
# Process the trivial stars (if any)
577+
if nb_trivial_star > 0
578+
for s in eachindex(hub)
579+
j = hub[s]
580+
if j < 0
581+
i = spokes[s][1]
582+
j = abs(j)
583+
if color_used[color[i]]
584+
# Make i the hub to avoid possibly adding one more used color
585+
# Switch it with the (only) spoke
586+
hub[s] = i
587+
spokes[s][1] = j
588+
else
589+
# Keep j as the hub
590+
color_used[color[j]] = true
591+
end
592+
end
593+
end
550594
end
551595
else
552596
# only the colors of non-leaf vertices are used

src/decompression.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ function decompress!(
426426
end
427427
end
428428
for s in eachindex(hub, spokes)
429-
j = hub[s]
429+
j = abs(hub[s])
430430
cj = color[j]
431431
for i in spokes[s]
432432
if in_triangle(i, j, uplo)

0 commit comments

Comments
 (0)