@@ -683,8 +683,9 @@ function postprocess!(
683683 end
684684
685685 # Process the trivial stars (if any)
686- nb_unknown_hubs = nb_trivial_stars
687686 if nb_trivial_stars > 0
687+ nb_unknown_hubs = nb_trivial_stars
688+
688689 rvS = rowvals (S)
689690 for j in axes (S, 2 )
690691 for k in nzrange (S, j)
@@ -712,35 +713,46 @@ function postprocess!(
712713 end
713714 end
714715 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
716+
717+ # Only trivial stars, where both vertices can be promoted as hubs, remain.
718+ # In the context of bicoloring, if we aim to minimize either the number of row colors or the number of column colors,
719+ # we can achieve optimal post-processing by choosing as hubs the vertices from the opposite partition.
720+ # This is optimal because we never increase the number of colors in the target partition during this phase,
721+ # and all preceding steps of the post-processing are 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+ h = abs (h)
734+ spoke = h == j ? i : j
735+ # We need to decide who is the hub
736+ if ! color_used[color[i]] && ! color_used[color[j]]
737+ if postprocessing_minimizes == :row_colors
738+ # j belongs to a column partition in the context of bicoloring
739+ hub[s] = j
740+ color_used[color[j]] = true
741+ elseif postprocessing_minimizes == :column_colors
742+ # i belongs to a row partition in the context of bicoloring
743+ hub[s] = i
744+ color_used[color[i]] = true
745+ else postprocessing_minimizes == :all_colors
746+ # We don't do anything special
747+ hub[s] = h
748+ color_used[color[h]] = true
749+ end
750+ else
751+ # Ensure that we use the correct hub for the decompression
752+ if color_used[color[spoke]] && ! color_used[color[h]]
753+ hub[s] = spoke
754+ end
755+ end
744756 end
745757 end
746758 end
@@ -821,6 +833,8 @@ function postprocess!(
821833
822834 # Process the trivial trees (if any)
823835 if nb_trivial_trees > 0
836+ nb_unknown_roots = nb_trivial_trees
837+
824838 for k in 1 : nt
825839 # Position of the first edge in the tree
826840 first = tree_edge_indices[k]
@@ -831,13 +845,55 @@ function postprocess!(
831845 # Check if we have exactly one edge in the tree
832846 if ne_tree == 1
833847 (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)
848+ if color_used[color[j]]
849+ # The current root of this trivial tree is already an internal node in a non-trivial tree
850+ nb_unknown_roots -= 1
838851 else
839- # Keep j as the root
840- color_used[color[j]] = true
852+ if color_used[color[i]]
853+ # The current leaf of this trivial tree is also an internal node in a non-trivial tree
854+ # Switch the root and the leaf to avoid adding one more used color
855+ reverse_bfs_orders[first] = (j, i)
856+ nb_unknown_roots -= 1
857+ end
858+ end
859+ end
860+ end
861+
862+ # Only trivial trees, where both vertices can be promoted as roots, remain.
863+ # In the context of bicoloring, if we aim to minimize either the number of row colors or the number of column colors,
864+ # we can achieve optimal post-processing by choosing as roots the vertices from the opposite partition.
865+ # This is optimal because we never increase the number of colors in the target partition during this phase,
866+ # and all preceding steps of the post-processing are deterministic.
867+ if nb_unknown_roots > 0
868+ for k in 1 : nt
869+ # Position of the first edge in the tree
870+ first = tree_edge_indices[k]
871+
872+ # Total number of edges in the tree
873+ ne_tree = tree_edge_indices[k + 1 ] - first
874+
875+ # Check if we have exactly one edge in the tree
876+ if ne_tree == 1
877+ (i, j) = reverse_bfs_orders[first]
878+ if ! color_used[color[i]] && ! color_used[color[j]]
879+ if postprocessing_minimizes == :row_colors
880+ # v belongs to a column partition in the context of bicoloring
881+ v = min (i,j)
882+ color_used[color[v]] = true
883+ elseif postprocessing_minimizes == :column_colors
884+ # v belongs to a row partition in the context of bicoloring
885+ v = max (i,j)
886+ color_used[color[v]] = true
887+ else postprocessing_minimizes == :all_colors
888+ # We don't do anything special
889+ color_used[color[j]] = true
890+ end
891+ else
892+ # Ensure that we use the correct root for the decompression
893+ if color_used[color[i]] && ! color_used[color[j]]
894+ reverse_bfs_orders[first] = (j, i)
895+ end
896+ end
841897 end
842898 end
843899 end
0 commit comments