Skip to content

Commit fdb55e8

Browse files
committed
WIP
1 parent 390d009 commit fdb55e8

File tree

1 file changed

+147
-104
lines changed

1 file changed

+147
-104
lines changed

src/coloring.jl

Lines changed: 147 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -648,10 +648,10 @@ end
648648

649649
function postprocess!(
650650
color::AbstractVector{<:Integer},
651-
star_or_tree_set::Union{StarSet,TreeSet},
651+
star_set::StarSet,
652652
g::AdjacencyGraph,
653653
offsets::AbstractVector{<:Integer};
654-
neutralized_first::Symbol=:rows,
654+
postprocessing_minimizes::Symbol=:all_colors,
655655
)
656656
S = pattern(g)
657657
edge_to_index = edge_indices(g)
@@ -668,134 +668,177 @@ function postprocess!(
668668
end
669669
end
670670

671-
if star_or_tree_set isa StarSet
672-
# only the colors of the hubs are used
673-
(; star, hub) = star_or_tree_set
674-
nb_trivial_stars = 0
671+
# only the colors of the hubs are used
672+
(; star, hub) = star_set
673+
nb_trivial_stars = 0
675674

676-
# Iterate through all non-trivial stars
677-
for s in eachindex(hub)
678-
h = hub[s]
679-
if h > 0
680-
color_used[color[h]] = true
681-
else
682-
nb_trivial_stars += 1
683-
end
675+
# Iterate through all non-trivial stars
676+
for s in eachindex(hub)
677+
h = hub[s]
678+
if h > 0
679+
color_used[color[h]] = true
680+
else
681+
nb_trivial_stars += 1
684682
end
683+
end
685684

686-
# Process the trivial stars (if any)
687-
nb_unknown_hubs = nb_trivial_stars
688-
if nb_trivial_stars > 0
689-
rvS = rowvals(S)
690-
for j in axes(S, 2)
691-
for k in nzrange(S, j)
692-
i = rvS[k]
693-
if i > j
694-
index_ij = edge_to_index[k]
695-
s = star[index_ij]
696-
h = hub[s]
697-
if h < 0
698-
h = abs(h)
699-
spoke = h == j ? i : j
700-
if color_used[color[h]]
701-
# The current hub of this trivial star is already a hub in a non-trivial star
702-
hub[s] = h
685+
# Process the trivial stars (if any)
686+
nb_unknown_hubs = nb_trivial_stars
687+
if nb_trivial_stars > 0
688+
rvS = rowvals(S)
689+
for j in axes(S, 2)
690+
for k in nzrange(S, j)
691+
i = rvS[k]
692+
if i > j
693+
index_ij = edge_to_index[k]
694+
s = star[index_ij]
695+
h = hub[s]
696+
if h < 0
697+
h = abs(h)
698+
spoke = h == j ? i : j
699+
if color_used[color[h]]
700+
# The current hub of this trivial star is already a hub in a non-trivial star
701+
hub[s] = h
702+
nb_unknown_hubs -= 1
703+
else
704+
if color_used[color[spoke]]
705+
# The current spoke of this trivial star is also a hub in a non-trivial star
706+
# Switch the hub and the spoke to avoid adding one more used color
707+
hub[s] = spoke
703708
nb_unknown_hubs -= 1
704-
else
705-
if color_used[color[spoke]]
706-
# The current spoke of this trivial star is also a hub in a non-trivial star
707-
# Switch the hub and the spoke to avoid adding one more used color
708-
hub[s] = spoke
709-
nb_unknown_hubs -= 1
710-
end
711709
end
712710
end
713711
end
714712
end
715713
end
716714
end
717-
# Only trivial stars where both vertices can be promoted as hub are remaining.
718-
# In the context of bicoloring, if we want to minimize the number of row colors OR the number of column colors,
719-
# we can have the optimal post-processing by taking as hub the vertices in the other partition.
720-
# It is optimal because we will never increase the number of colors in the partition specified by `neutralized_first`
721-
# in this phase and everything else in the post-processing is deterministic.
722-
if nb_unknown_hubs > 0
723-
rvS = rowvals(S)
724-
for j in axes(S, 2)
725-
for k in nzrange(S, j)
726-
i = rvS[k]
727-
if i > j
728-
index_ij = edge_to_index[k]
729-
s = star[index_ij]
730-
h = hub[s]
731-
# The hub of this trivial star is still unknown
732-
if h < 0
733-
if neutralized_first == :rows
734-
# j represents a column in the context of bicoloring
735-
hub[s] = j
736-
color_used[color[j]] = true
737-
else # neutralized_first == :cols
738-
# i represents a row in the context of bicoloring
739-
hub[s] = i
740-
color_used[color[i]] = true
741-
end
715+
end
716+
# Only trivial stars, where both vertices can be promoted as hubs, remain.
717+
# In the context of bicoloring, if we aim to minimize either the number of row colors or the number of column colors,
718+
# we can achieve optimal post-processing by choosing as hubs the vertices from the opposite partition.
719+
# This is optimal because we never increase the number of colors in the target partition during this phase,
720+
# and all preceding steps of the post-processing are deterministic.
721+
if nb_unknown_hubs > 0
722+
rvS = rowvals(S)
723+
for j in axes(S, 2)
724+
for k in nzrange(S, j)
725+
i = rvS[k]
726+
if i > j
727+
index_ij = edge_to_index[k]
728+
s = star[index_ij]
729+
h = hub[s]
730+
# The hub of this trivial star is still unknown
731+
if h < 0
732+
if postprocessing_minimizes == :row_colors
733+
# j bzlongs to a column partition in the context of bicoloring
734+
hub[s] = j
735+
color_used[color[j]] = true
736+
elseif postprocessing_minimizes == :column_colors
737+
# i belongs to a row partition in the context of bicoloring
738+
hub[s] = i
739+
color_used[color[i]] = true
740+
else postprocessing_minimizes == :all_colors
741+
l = abs(h)
742+
hub[s] = l
743+
color_used[color[l]] = true
742744
end
743745
end
744746
end
745747
end
746748
end
747-
else
748-
# only the colors of non-leaf vertices are used
749-
(; reverse_bfs_orders, is_star, tree_edge_indices, nt) = star_or_tree_set
750-
nb_trivial_trees = 0
749+
end
750+
751+
# if at least one of the colors is useless, modify the color assignments of vertices
752+
if any(!, color_used)
753+
num_colors_useless = 0
751754

752-
# Iterate through all non-trivial trees
755+
# determine what are the useless colors and compute the offsets
756+
for ci in 1:nb_colors
757+
if color_used[ci]
758+
offsets[ci] = num_colors_useless
759+
else
760+
num_colors_useless += 1
761+
end
762+
end
763+
764+
# assign the neutral color to every vertex with a useless color and remap the colors
765+
for i in eachindex(color)
766+
ci = color[i]
767+
if !color_used[ci]
768+
# assign the neutral color
769+
color[i] = 0
770+
else
771+
# remap the color to not have any gap
772+
color[i] -= offsets[ci]
773+
end
774+
end
775+
end
776+
return color
777+
end
778+
779+
function postprocess!(
780+
color::AbstractVector{<:Integer},
781+
tree_set::TreeSet,
782+
g::AdjacencyGraph,
783+
offsets::AbstractVector{<:Integer};
784+
postprocessing_minimizes::Symbol=:all_colors,
785+
)
786+
S = pattern(g)
787+
edge_to_index = edge_indices(g)
788+
# flag which colors are actually used during decompression
789+
nb_colors = maximum(color)
790+
color_used = zeros(Bool, nb_colors)
791+
792+
# only the colors of non-leaf vertices are used
793+
(; reverse_bfs_orders, is_star, tree_edge_indices, nt) = tree_set
794+
nb_trivial_trees = 0
795+
796+
# Iterate through all non-trivial trees
797+
for k in 1:nt
798+
# Position of the first edge in the tree
799+
first = tree_edge_indices[k]
800+
801+
# Total number of edges in the tree
802+
ne_tree = tree_edge_indices[k + 1] - first
803+
804+
# Check if we have more than one edge in the tree (non-trivial tree)
805+
if ne_tree > 1
806+
# Determine if the tree is a star
807+
if is_star[k]
808+
# It is a non-trivial star and only the color of the hub is needed
809+
(_, hub) = reverse_bfs_orders[first]
810+
color_used[color[hub]] = true
811+
else
812+
# It is not a star and both colors are needed during the decompression
813+
(i, j) = reverse_bfs_orders[first]
814+
color_used[color[i]] = true
815+
color_used[color[j]] = true
816+
end
817+
else
818+
nb_trivial_trees += 1
819+
end
820+
end
821+
822+
# Process the trivial trees (if any)
823+
if nb_trivial_trees > 0
753824
for k in 1:nt
754825
# Position of the first edge in the tree
755826
first = tree_edge_indices[k]
756827

757828
# Total number of edges in the tree
758829
ne_tree = tree_edge_indices[k + 1] - first
759830

760-
# Check if we have more than one edge in the tree (non-trivial tree)
761-
if ne_tree > 1
762-
# Determine if the tree is a star
763-
if is_star[k]
764-
# It is a non-trivial star and only the color of the hub is needed
765-
(_, hub) = reverse_bfs_orders[first]
766-
color_used[color[hub]] = true
831+
# Check if we have exactly one edge in the tree
832+
if ne_tree == 1
833+
(i, j) = reverse_bfs_orders[first]
834+
if color_used[color[i]]
835+
# Make i the root to avoid possibly adding one more used color
836+
# Switch it with the (only) leaf
837+
reverse_bfs_orders[first] = (j, i)
767838
else
768-
# It is not a star and both colors are needed during the decompression
769-
(i, j) = reverse_bfs_orders[first]
770-
color_used[color[i]] = true
839+
# Keep j as the root
771840
color_used[color[j]] = true
772841
end
773-
else
774-
nb_trivial_trees += 1
775-
end
776-
end
777-
778-
# Process the trivial trees (if any)
779-
if nb_trivial_trees > 0
780-
for k in 1:nt
781-
# Position of the first edge in the tree
782-
first = tree_edge_indices[k]
783-
784-
# Total number of edges in the tree
785-
ne_tree = tree_edge_indices[k + 1] - first
786-
787-
# Check if we have exactly one edge in the tree
788-
if ne_tree == 1
789-
(i, j) = reverse_bfs_orders[first]
790-
if color_used[color[i]]
791-
# Make i the root to avoid possibly adding one more used color
792-
# Switch it with the (only) leaf
793-
reverse_bfs_orders[first] = (j, i)
794-
else
795-
# Keep j as the root
796-
color_used[color[j]] = true
797-
end
798-
end
799842
end
800843
end
801844
end

0 commit comments

Comments
 (0)