Skip to content

Commit 3bf7557

Browse files
committed
WIP
1 parent 7cea5ed commit 3bf7557

1 file changed

Lines changed: 148 additions & 105 deletions

File tree

src/coloring.jl

Lines changed: 148 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,10 @@ end
606606

607607
function postprocess!(
608608
color::AbstractVector{<:Integer},
609-
star_or_tree_set::Union{StarSet,TreeSet},
609+
star_set::StarSet,
610610
g::AdjacencyGraph,
611611
offsets::AbstractVector{<:Integer};
612-
neutralized_first::Symbol=:rows,
612+
postprocessing_minimizes::Symbol=:all_colors,
613613
)
614614
S = pattern(g)
615615
edge_to_index = edge_indices(g)
@@ -626,134 +626,177 @@ function postprocess!(
626626
end
627627
end
628628

629-
if star_or_tree_set isa StarSet
630-
# only the colors of the hubs are used
631-
(; star, hub) = star_or_tree_set
632-
nb_trivial_stars = 0
633-
634-
# Iterate through all non-trivial stars
635-
for s in eachindex(hub)
636-
h = hub[s]
637-
if h > 0
638-
color_used[color[h]] = true
639-
else
640-
nb_trivial_stars += 1
641-
end
629+
# only the colors of the hubs are used
630+
(; star, hub) = star_set
631+
nb_trivial_stars = 0
632+
633+
# Iterate through all non-trivial stars
634+
for s in eachindex(hub)
635+
h = hub[s]
636+
if h > 0
637+
color_used[color[h]] = true
638+
else
639+
nb_trivial_stars += 1
642640
end
641+
end
643642

644-
# Process the trivial stars (if any)
645-
nb_unknown_hubs = nb_trivial_stars
646-
if nb_trivial_stars > 0
647-
rvS = rowvals(S)
648-
for j in axes(S, 2)
649-
for k in nzrange(S, j)
650-
i = rvS[k]
651-
if i > j
652-
index_ij = edge_to_index[k]
653-
s = star[index_ij]
654-
h = hub[s]
655-
if h < 0
656-
h = abs(h)
657-
spoke = h == j ? i : j
658-
if color_used[color[h]]
659-
# The current hub of this trivial star is already a hub in a non-trivial star
660-
hub[s] = h
643+
# Process the trivial stars (if any)
644+
nb_unknown_hubs = nb_trivial_stars
645+
if nb_trivial_stars > 0
646+
rvS = rowvals(S)
647+
for j in axes(S, 2)
648+
for k in nzrange(S, j)
649+
i = rvS[k]
650+
if i > j
651+
index_ij = edge_to_index[k]
652+
s = star[index_ij]
653+
h = hub[s]
654+
if h < 0
655+
h = abs(h)
656+
spoke = h == j ? i : j
657+
if color_used[color[h]]
658+
# The current hub of this trivial star is already a hub in a non-trivial star
659+
hub[s] = h
660+
nb_unknown_hubs -= 1
661+
else
662+
if color_used[color[spoke]]
663+
# The current spoke of this trivial star is also a hub in a non-trivial star
664+
# Switch the hub and the spoke to avoid adding one more used color
665+
hub[s] = spoke
661666
nb_unknown_hubs -= 1
662-
else
663-
if color_used[color[spoke]]
664-
# The current spoke of this trivial star is also a hub in a non-trivial star
665-
# Switch the hub and the spoke to avoid adding one more used color
666-
hub[s] = spoke
667-
nb_unknown_hubs -= 1
668-
end
669667
end
670668
end
671669
end
672670
end
673671
end
674672
end
675-
# Only trivial stars where both vertices can be promoted as hub are remaining.
676-
# In the context of bicoloring, if we want to minimize the number of row colors OR the number of column colors,
677-
# we can have the optimal post-processing by taking as hub the vertices in the other partition.
678-
# It is optimal because we will never increase the number of colors in the partition specified by `neutralized_first`
679-
# in this phase and everything else in the post-processing is deterministic.
680-
if nb_unknown_hubs > 0
681-
rvS = rowvals(S)
682-
for j in axes(S, 2)
683-
for k in nzrange(S, j)
684-
i = rvS[k]
685-
if i > j
686-
index_ij = edge_to_index[k]
687-
s = star[index_ij]
688-
h = hub[s]
689-
# The hub of this trivial star is still unknown
690-
if h < 0
691-
if neutralized_first == :rows
692-
# j represents a column in the context of bicoloring
693-
hub[s] = j
694-
color_used[color[j]] = true
695-
else # neutralized_first == :cols
696-
# i represents a row in the context of bicoloring
697-
hub[s] = i
698-
color_used[color[i]] = true
699-
end
673+
end
674+
# Only trivial stars, where both vertices can be promoted as hubs, remain.
675+
# In the context of bicoloring, if we aim to minimize either the number of row colors or the number of column colors,
676+
# we can achieve optimal post-processing by choosing as hubs the vertices from the opposite partition.
677+
# This is optimal because we never increase the number of colors in the target partition during this phase,
678+
# and all preceding steps of the post-processing are deterministic.
679+
if nb_unknown_hubs > 0
680+
rvS = rowvals(S)
681+
for j in axes(S, 2)
682+
for k in nzrange(S, j)
683+
i = rvS[k]
684+
if i > j
685+
index_ij = edge_to_index[k]
686+
s = star[index_ij]
687+
h = hub[s]
688+
# The hub of this trivial star is still unknown
689+
if h < 0
690+
if postprocessing_minimizes == :row_colors
691+
# j bzlongs to a column partition in the context of bicoloring
692+
hub[s] = j
693+
color_used[color[j]] = true
694+
elseif postprocessing_minimizes == :column_colors
695+
# i belongs to a row partition in the context of bicoloring
696+
hub[s] = i
697+
color_used[color[i]] = true
698+
else postprocessing_minimizes == :all_colors
699+
l = abs(h)
700+
hub[s] = l
701+
color_used[color[l]] = true
700702
end
701703
end
702704
end
703705
end
704706
end
705-
else
706-
# only the colors of non-leaf vertices are used
707-
(; reverse_bfs_orders, is_star, tree_edge_indices, nt) = star_or_tree_set
708-
nb_trivial_trees = 0
707+
end
708+
709+
# if at least one of the colors is useless, modify the color assignments of vertices
710+
if any(!, color_used)
711+
num_colors_useless = 0
712+
713+
# determine what are the useless colors and compute the offsets
714+
for ci in 1:nb_colors
715+
if color_used[ci]
716+
offsets[ci] = num_colors_useless
717+
else
718+
num_colors_useless += 1
719+
end
720+
end
721+
722+
# assign the neutral color to every vertex with a useless color and remap the colors
723+
for i in eachindex(color)
724+
ci = color[i]
725+
if !color_used[ci]
726+
# assign the neutral color
727+
color[i] = 0
728+
else
729+
# remap the color to not have any gap
730+
color[i] -= offsets[ci]
731+
end
732+
end
733+
end
734+
return color
735+
end
736+
737+
function postprocess!(
738+
color::AbstractVector{<:Integer},
739+
tree_set::TreeSet,
740+
g::AdjacencyGraph,
741+
offsets::AbstractVector{<:Integer};
742+
postprocessing_minimizes::Symbol=:all_colors,
743+
)
744+
S = pattern(g)
745+
edge_to_index = edge_indices(g)
746+
# flag which colors are actually used during decompression
747+
nb_colors = maximum(color)
748+
color_used = zeros(Bool, nb_colors)
749+
750+
# only the colors of non-leaf vertices are used
751+
(; reverse_bfs_orders, is_star, tree_edge_indices, nt) = tree_set
752+
nb_trivial_trees = 0
753+
754+
# Iterate through all non-trivial trees
755+
for k in 1:nt
756+
# Position of the first edge in the tree
757+
first = tree_edge_indices[k]
758+
759+
# Total number of edges in the tree
760+
ne_tree = tree_edge_indices[k + 1] - first
761+
762+
# Check if we have more than one edge in the tree (non-trivial tree)
763+
if ne_tree > 1
764+
# Determine if the tree is a star
765+
if is_star[k]
766+
# It is a non-trivial star and only the color of the hub is needed
767+
(_, hub) = reverse_bfs_orders[first]
768+
color_used[color[hub]] = true
769+
else
770+
# It is not a star and both colors are needed during the decompression
771+
(i, j) = reverse_bfs_orders[first]
772+
color_used[color[i]] = true
773+
color_used[color[j]] = true
774+
end
775+
else
776+
nb_trivial_trees += 1
777+
end
778+
end
709779

710-
# Iterate through all non-trivial trees
780+
# Process the trivial trees (if any)
781+
if nb_trivial_trees > 0
711782
for k in 1:nt
712783
# Position of the first edge in the tree
713784
first = tree_edge_indices[k]
714785

715786
# Total number of edges in the tree
716787
ne_tree = tree_edge_indices[k + 1] - first
717788

718-
# Check if we have more than one edge in the tree (non-trivial tree)
719-
if ne_tree > 1
720-
# Determine if the tree is a star
721-
if is_star[k]
722-
# It is a non-trivial star and only the color of the hub is needed
723-
(_, hub) = reverse_bfs_orders[first]
724-
color_used[color[hub]] = true
789+
# Check if we have exactly one edge in the tree
790+
if ne_tree == 1
791+
(i, j) = reverse_bfs_orders[first]
792+
if color_used[color[i]]
793+
# Make i the root to avoid possibly adding one more used color
794+
# Switch it with the (only) leaf
795+
reverse_bfs_orders[first] = (j, i)
725796
else
726-
# It is not a star and both colors are needed during the decompression
727-
(i, j) = reverse_bfs_orders[first]
728-
color_used[color[i]] = true
797+
# Keep j as the root
729798
color_used[color[j]] = true
730799
end
731-
else
732-
nb_trivial_trees += 1
733-
end
734-
end
735-
736-
# Process the trivial trees (if any)
737-
if nb_trivial_trees > 0
738-
for k in 1:nt
739-
# Position of the first edge in the tree
740-
first = tree_edge_indices[k]
741-
742-
# Total number of edges in the tree
743-
ne_tree = tree_edge_indices[k + 1] - first
744-
745-
# Check if we have exactly one edge in the tree
746-
if ne_tree == 1
747-
(i, j) = reverse_bfs_orders[first]
748-
if color_used[color[i]]
749-
# Make i the root to avoid possibly adding one more used color
750-
# Switch it with the (only) leaf
751-
reverse_bfs_orders[first] = (j, i)
752-
else
753-
# Keep j as the root
754-
color_used[color[j]] = true
755-
end
756-
end
757800
end
758801
end
759802
end

0 commit comments

Comments
 (0)