Skip to content

Commit a0176ac

Browse files
committed
Add an heuristic for :all_colors
1 parent c1724ab commit a0176ac

1 file changed

Lines changed: 99 additions & 50 deletions

File tree

src/postprocessing.jl

Lines changed: 99 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ function postprocess!(
2222

2323
if star_or_tree_set isa StarSet
2424
# star_or_tree_set is a StarSet
25-
postprocess_star_coloring!(g, color_used, color, star_or_tree_set)
25+
postprocess_star_coloring!(g, color_used, color, star_or_tree_set, offsets)
2626
else
2727
# star_or_tree_set is a TreeSet
28-
postprocess_acyclic_coloring!(color_used, color, star_or_tree_set)
28+
postprocess_acyclic_coloring!(color_used, color, star_or_tree_set, offsets)
2929
end
3030
else
3131
row_color_used = zeros(Bool, nb_colors)
3232
column_color_used = color_used
3333

3434
if star_or_tree_set isa StarSet
3535
# star_or_tree_set is a StarSet
36-
postprocess_star_bicoloring!(g, row_color_used, column_color_used, color, star_or_tree_set, postprocessing_minimizes)
36+
postprocess_star_bicoloring!(g, row_color_used, column_color_used, color, star_or_tree_set, offsets, postprocessing_minimizes)
3737
else
3838
# star_or_tree_set is a TreeSet
39-
postprocess_acyclic_bicoloring!(row_color_used, column_color_used, color, star_or_tree_set, postprocessing_minimizes)
39+
postprocess_acyclic_bicoloring!(row_color_used, column_color_used, color, star_or_tree_set, offsets, postprocessing_minimizes)
4040
end
4141

4242
# Identify colors that are used in either the row or column partition
@@ -78,6 +78,7 @@ function postprocess_star_coloring!(
7878
color_used::Vector{Bool},
7979
color::AbstractVector{<:Integer},
8080
star_set::StarSet,
81+
occurrences::AbstractVector{<:Integer},
8182
)
8283
S = pattern(g)
8384
edge_to_index = edge_indices(g)
@@ -98,7 +99,8 @@ function postprocess_star_coloring!(
9899

99100
# Process the trivial stars (if any)
100101
if nb_trivial_stars > 0
101-
nb_unknown_hubs = nb_trivial_stars
102+
occurrences .= 0
103+
all_trivial_stars_treated = true
102104

103105
rvS = rowvals(S)
104106
for j in axes(S, 2)
@@ -113,14 +115,17 @@ function postprocess_star_coloring!(
113115
if color_used[color[h]]
114116
# The current hub of this trivial star is already a hub in a non-trivial star
115117
hub[s] = h
116-
nb_unknown_hubs -= 1
117118
else
118119
spoke = h == j ? i : j
119120
if color_used[color[spoke]]
120121
# The current spoke of this trivial star is also a hub in a non-trivial star
121122
# Switch the hub and the spoke to avoid adding one more used color
122123
hub[s] = spoke
123-
nb_unknown_hubs -= 1
124+
else
125+
all_trivial_stars_treated = false
126+
# Increment the occurrence count of vertices i and j within the remaining set of trivial stars
127+
occurrences[i] += 1
128+
occurrences[j] += 1
124129
end
125130
end
126131
end
@@ -129,7 +134,7 @@ function postprocess_star_coloring!(
129134
end
130135

131136
# Only trivial stars, where both vertices can be promoted as hubs, remain.
132-
if nb_unknown_hubs > 0
137+
if !all_trivial_stars_treated
133138
rvS = rowvals(S)
134139
for j in axes(S, 2)
135140
for k in nzrange(S, j)
@@ -140,17 +145,24 @@ function postprocess_star_coloring!(
140145
h = hub[s]
141146
# The hub of this trivial star is still unknown
142147
if h < 0
143-
h = abs(h)
144148
# We need to decide who is the hub
145149
if !color_used[color[i]] && !color_used[color[j]]
146-
# We don't do anything special
147-
hub[s] = h
148-
color_used[color[h]] = true
150+
# We use the vertex with the highest occurrence as the hub
151+
# This is a heuristic to maximize the number of vertices with a neutral color
152+
# and may indirectly reduce the number of colors needed
153+
if occurrences[j] > occurrences[i]
154+
hub[s] = j
155+
color_used[color[j]] = true
156+
else
157+
hub[s] = i
158+
color_used[color[i]] = true
159+
end
149160
else
150-
# Ensure that the hub vertex has a used color for decompression
151-
spoke = h == j ? i : j
152-
if color_used[color[spoke]] && !color_used[color[h]]
153-
hub[s] = spoke
161+
# Previously processed trivial stars determined the hub vertex for this star
162+
if color_used[color[i]]
163+
hub[s] = i
164+
else
165+
hub[s] = j
154166
end
155167
end
156168
end
@@ -168,6 +180,7 @@ function postprocess_star_bicoloring!(
168180
column_color_used::Vector{Bool},
169181
color::AbstractVector{<:Integer},
170182
star_set::StarSet,
183+
occurrences::AbstractVector{<:Integer},
171184
postprocessing_minimizes::Symbol=:all_colors,
172185
)
173186
S = pattern(g)
@@ -196,7 +209,8 @@ function postprocess_star_bicoloring!(
196209

197210
# Process the trivial stars (if any)
198211
if nb_trivial_stars > 0
199-
nb_unknown_hubs = nb_trivial_stars
212+
occurrences .= 0
213+
all_trivial_stars_treated = true
200214

201215
rvS = rowvals(S)
202216
for j in axes(S, 2)
@@ -211,14 +225,17 @@ function postprocess_star_bicoloring!(
211225
if (h n ? column_color_used[color[h]] : row_color_used[color[h]])
212226
# The current hub of this trivial star is already a hub in a non-trivial star
213227
hub[s] = h
214-
nb_unknown_hubs -= 1
215228
else
216229
spoke = h == j ? i : j
217230
if (spoke n ? column_color_used[color[spoke]] : row_color_used[color[spoke]])
218231
# The current spoke of this trivial star is also a hub in a non-trivial star
219232
# Switch the hub and the spoke to avoid adding one more used color
220233
hub[s] = spoke
221-
nb_unknown_hubs -= 1
234+
else
235+
all_trivial_stars_treated = false
236+
# Increment the occurrence count of vertices i and j within the remaining set of trivial stars
237+
occurrences[i] += 1
238+
occurrences[j] += 1
222239
end
223240
end
224241
end
@@ -231,7 +248,7 @@ function postprocess_star_bicoloring!(
231248
# we can achieve optimal post-processing by choosing as hubs the vertices from the opposite partition.
232249
# This is optimal because we never increase the number of colors in the target partition during this phase,
233250
# and all preceding steps of the post-processing are deterministic.
234-
if nb_unknown_hubs > 0
251+
if !all_trivial_stars_treated
235252
rvS = rowvals(S)
236253
for j in axes(S, 2)
237254
for k in nzrange(S, j)
@@ -253,29 +270,25 @@ function postprocess_star_bicoloring!(
253270
hub[s] = i
254271
row_color_used[color[i]] = true
255272
elseif postprocessing_minimizes == :all_colors
256-
# We don't do anything special
257-
h = abs(h)
258-
hub[s] = h
259-
if h n
260-
column_color_used[color[h]] = true
273+
# We use the vertex with the highest occurrence as the hub
274+
# This is a heuristic to maximize the number of vertices with a neutral color
275+
# and may indirectly reduce the number of colors needed
276+
if occurrences[j] > occurrences[i]
277+
hub[s] = j
278+
column_color_used[color[j]] = true
261279
else
262-
row_color_used[color[h]] = true
280+
hub[s] = i
281+
row_color_used[color[i]] = true
263282
end
264283
else
265284
error("The value postprocessing_minimizes = :$postprocessing_minimizes is not supported.")
266285
end
267286
else
268-
# Ensure that the hub vertex has a used color for decompression
269-
h = abs(h)
270-
spoke = h == j ? i : j
271-
if h n
272-
if row_color_used[color[spoke]] && !column_color_used[color[h]]
273-
hub[s] = spoke
274-
end
287+
# Previously processed trivial stars determined the hub vertex for this star
288+
if row_color_used[color[i]]
289+
hub[s] = i
275290
else
276-
if column_color_used[color[spoke]] && !row_color_used[color[h]]
277-
hub[s] = spoke
278-
end
291+
hub[s] = j
279292
end
280293
end
281294
end
@@ -291,6 +304,7 @@ function postprocess_acyclic_coloring!(
291304
color_used::Vector{Bool},
292305
color::AbstractVector{<:Integer},
293306
tree_set::TreeSet,
307+
occurrences::AbstractVector{<:Integer},
294308
)
295309
# only the colors of non-leaf vertices are used
296310
(; reverse_bfs_orders, is_star, tree_edge_indices, nt) = tree_set
@@ -324,7 +338,8 @@ function postprocess_acyclic_coloring!(
324338

325339
# Process the trivial trees (if any)
326340
if nb_trivial_trees > 0
327-
nb_unknown_roots = nb_trivial_trees
341+
occurrences .= 0
342+
all_trivial_trees_treated = true
328343

329344
for k in 1:nt
330345
# Position of the first edge in the tree
@@ -338,20 +353,23 @@ function postprocess_acyclic_coloring!(
338353
(i, j) = reverse_bfs_orders[first]
339354
if color_used[color[j]]
340355
# The current root of this trivial tree is already an internal node in a non-trivial tree
341-
nb_unknown_roots -= 1
342356
else
343357
if color_used[color[i]]
344358
# The current leaf of this trivial tree is also an internal node in a non-trivial tree
345359
# Switch the root and the leaf to avoid adding one more used color
346360
reverse_bfs_orders[first] = (j, i)
347-
nb_unknown_roots -= 1
361+
else
362+
all_trivial_trees_treated = false
363+
# Increment the occurrence count of vertices i and j within the remaining set of trivial trees
364+
occurrences[i] += 1
365+
occurrences[j] += 1
348366
end
349367
end
350368
end
351369
end
352370

353371
# Only trivial trees, where both vertices can be promoted as roots, remain.
354-
if nb_unknown_roots > 0
372+
if !all_trivial_trees_treated
355373
for k in 1:nt
356374
# Position of the first edge in the tree
357375
first = tree_edge_indices[k]
@@ -363,9 +381,17 @@ function postprocess_acyclic_coloring!(
363381
if ne_tree == 1
364382
(i, j) = reverse_bfs_orders[first]
365383
if !color_used[color[i]] && !color_used[color[j]]
366-
# We don't do anything special
367-
color_used[color[j]] = true
384+
# We use the vertex with the highest occurrence as the root
385+
# This is a heuristic to maximize the number of vertices with a neutral color
386+
# and may indirectly reduce the number of colors needed
387+
if occurrences[j] > occurrences[i]
388+
color_used[color[j]] = true
389+
else
390+
reverse_bfs_orders[first] = (j, i)
391+
color_used[color[i]] = true
392+
end
368393
else
394+
# Previously processed trivial trees determined the root vertex for this tree
369395
# Ensure that the root vertex has a used color for decompression
370396
if color_used[color[i]] && !color_used[color[j]]
371397
reverse_bfs_orders[first] = (j, i)
@@ -383,6 +409,7 @@ function postprocess_acyclic_bicoloring!(
383409
column_color_used::Vector{Bool},
384410
color::AbstractVector{<:Integer},
385411
tree_set::TreeSet,
412+
occurrences::AbstractVector{<:Integer},
386413
postprocessing_minimizes::Symbol=:all_colors,
387414
)
388415
# only the colors of non-leaf vertices are used
@@ -426,7 +453,8 @@ function postprocess_acyclic_bicoloring!(
426453

427454
# Process the trivial trees (if any)
428455
if nb_trivial_trees > 0
429-
nb_unknown_roots = nb_trivial_trees
456+
occurrences .= 0
457+
all_trivial_trees_treated = true
430458

431459
for k in 1:nt
432460
# Position of the first edge in the tree
@@ -440,13 +468,16 @@ function postprocess_acyclic_bicoloring!(
440468
(i, j) = reverse_bfs_orders[first]
441469
if (i < j ? row_color_used[color[j]] : column_color_used[color[j]])
442470
# The current root of this trivial tree is already an internal node in a non-trivial tree
443-
nb_unknown_roots -= 1
444471
else
445472
if (i < j ? column_color_used[color[i]] : row_color_used[color[i]])
446473
# The current leaf of this trivial tree is also an internal node in a non-trivial tree
447474
# Switch the root and the leaf to avoid adding one more used color
448475
reverse_bfs_orders[first] = (j, i)
449-
nb_unknown_roots -= 1
476+
else
477+
all_trivial_trees_treated = false
478+
# Increment the occurrence count of vertices i and j within the remaining set of trivial trees
479+
occurrences[i] += 1
480+
occurrences[j] += 1
450481
end
451482
end
452483
end
@@ -457,7 +488,7 @@ function postprocess_acyclic_bicoloring!(
457488
# we can achieve optimal post-processing by choosing as roots the vertices from the opposite partition.
458489
# This is optimal because we never increase the number of colors in the target partition during this phase,
459490
# and all preceding steps of the post-processing are deterministic.
460-
if nb_unknown_roots > 0
491+
if !all_trivial_trees_treated
461492
for k in 1:nt
462493
# Position of the first edge in the tree
463494
first = tree_edge_indices[k]
@@ -473,21 +504,39 @@ function postprocess_acyclic_bicoloring!(
473504
# v belongs to a column partition in the context of bicoloring
474505
v = min(i,j)
475506
column_color_used[color[v]] = true
507+
if v == i
508+
reverse_bfs_orders[first] = (j, i)
509+
end
476510
elseif postprocessing_minimizes == :column_colors
477511
# v belongs to a row partition in the context of bicoloring
478512
v = max(i,j)
479513
row_color_used[color[v]] = true
514+
if v == i
515+
reverse_bfs_orders[first] = (j, i)
516+
end
480517
elseif postprocessing_minimizes == :all_colors
481-
# We don't do anything special
482-
if i < j
483-
row_color_used[color[j]] = true
518+
# We use the vertex with the highest occurrence as the root
519+
# This is a heuristic to maximize the number of vertices with a neutral color
520+
# and may indirectly reduce the number of colors needed
521+
if occurrences[j] > occurrences[i]
522+
if i < j
523+
row_color_used[color[j]] = true
524+
else
525+
column_color_used[color[j]] = true
526+
end
484527
else
485-
column_color_used[color[j]] = true
528+
reverse_bfs_orders[first] = (j, i)
529+
if i < j
530+
column_color_used[color[i]] = true
531+
else
532+
row_color_used[color[i]] = true
533+
end
486534
end
487535
else
488536
error("The value postprocessing_minimizes = :$postprocessing_minimizes is not supported.")
489537
end
490538
else
539+
# Previously processed trivial trees determined the root vertex for this tree
491540
# Ensure that the root vertex has a used color for decompression
492541
if (i < j ? column_color_used[color[i]] && !row_color_used[color[j]] : row_color_used[color[i]] && !column_color_used[color[j]])
493542
reverse_bfs_orders[first] = (j, i)

0 commit comments

Comments
 (0)