From e3cbf67cf373978998b4055c14cf862825a1cb11 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Sat, 1 Nov 2025 01:05:57 -0500 Subject: [PATCH] Add a file postprocessing.jl --- src/SparseMatrixColorings.jl | 1 + src/coloring.jl | 147 ----------------------------------- src/postprocessing.jl | 146 ++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 147 deletions(-) create mode 100644 src/postprocessing.jl diff --git a/src/SparseMatrixColorings.jl b/src/SparseMatrixColorings.jl index fca70229..481c8584 100644 --- a/src/SparseMatrixColorings.jl +++ b/src/SparseMatrixColorings.jl @@ -47,6 +47,7 @@ include("graph.jl") include("forest.jl") include("order.jl") include("coloring.jl") +include("postprocessing.jl") include("result.jl") include("matrices.jl") include("interface.jl") diff --git a/src/coloring.jl b/src/coloring.jl index 7288b773..2746b30b 100644 --- a/src/coloring.jl +++ b/src/coloring.jl @@ -643,150 +643,3 @@ function TreeSet( return TreeSet(reverse_bfs_orders, is_star, tree_edge_indices, nt) end - -## Postprocessing, mirrors decompression code - -function postprocess!( - color::AbstractVector{<:Integer}, - star_or_tree_set::Union{StarSet,TreeSet}, - g::AdjacencyGraph, - offsets::AbstractVector{<:Integer}, -) - S = pattern(g) - edge_to_index = edge_indices(g) - # flag which colors are actually used during decompression - nb_colors = maximum(color) - color_used = zeros(Bool, nb_colors) - - # nonzero diagonal coefficients force the use of their respective color (there can be no neutral colors if the diagonal is fully nonzero) - if has_diagonal(g) - for i in axes(S, 1) - if !iszero(S[i, i]) - color_used[color[i]] = true - end - end - end - - if star_or_tree_set isa StarSet - # only the colors of the hubs are used - (; star, hub) = star_or_tree_set - nb_trivial_stars = 0 - - # Iterate through all non-trivial stars - for s in eachindex(hub) - h = hub[s] - if h > 0 - color_used[color[h]] = true - else - nb_trivial_stars += 1 - end - end - - # Process the trivial stars (if any) - if nb_trivial_stars > 0 - rvS = rowvals(S) - for j in axes(S, 2) - for k in nzrange(S, j) - i = rvS[k] - if i > j - index_ij = edge_to_index[k] - s = star[index_ij] - h = hub[s] - if h < 0 - h = abs(h) - spoke = h == j ? i : j - if color_used[color[spoke]] - # Switch the hub and the spoke to possibly avoid adding one more used color - hub[s] = spoke - else - # Keep the current hub - color_used[color[h]] = true - end - end - end - end - end - end - else - # only the colors of non-leaf vertices are used - (; reverse_bfs_orders, is_star, tree_edge_indices, nt) = star_or_tree_set - nb_trivial_trees = 0 - - # Iterate through all non-trivial trees - for k in 1:nt - # Position of the first edge in the tree - first = tree_edge_indices[k] - - # Total number of edges in the tree - ne_tree = tree_edge_indices[k + 1] - first - - # Check if we have more than one edge in the tree (non-trivial tree) - if ne_tree > 1 - # Determine if the tree is a star - if is_star[k] - # It is a non-trivial star and only the color of the hub is needed - (_, hub) = reverse_bfs_orders[first] - color_used[color[hub]] = true - else - # It is not a star and both colors are needed during the decompression - (i, j) = reverse_bfs_orders[first] - color_used[color[i]] = true - color_used[color[j]] = true - end - else - nb_trivial_trees += 1 - end - end - - # Process the trivial trees (if any) - if nb_trivial_trees > 0 - for k in 1:nt - # Position of the first edge in the tree - first = tree_edge_indices[k] - - # Total number of edges in the tree - ne_tree = tree_edge_indices[k + 1] - first - - # Check if we have exactly one edge in the tree - if ne_tree == 1 - (i, j) = reverse_bfs_orders[first] - if color_used[color[i]] - # Make i the root to avoid possibly adding one more used color - # Switch it with the (only) leaf - reverse_bfs_orders[first] = (j, i) - else - # Keep j as the root - color_used[color[j]] = true - end - end - end - end - end - - # if at least one of the colors is useless, modify the color assignments of vertices - if any(!, color_used) - num_colors_useless = 0 - - # determine what are the useless colors and compute the offsets - for ci in 1:nb_colors - if color_used[ci] - offsets[ci] = num_colors_useless - else - num_colors_useless += 1 - end - end - - # assign the neutral color to every vertex with a useless color and remap the colors - for i in eachindex(color) - ci = color[i] - if !color_used[ci] - # assign the neutral color - color[i] = 0 - else - # remap the color to not have any gap - color[i] -= offsets[ci] - end - end - end - return color -end diff --git a/src/postprocessing.jl b/src/postprocessing.jl new file mode 100644 index 00000000..217b663b --- /dev/null +++ b/src/postprocessing.jl @@ -0,0 +1,146 @@ +## Postprocessing + +function postprocess!( + color::AbstractVector{<:Integer}, + star_or_tree_set::Union{StarSet,TreeSet}, + g::AdjacencyGraph, + offsets::AbstractVector{<:Integer}, +) + S = pattern(g) + edge_to_index = edge_indices(g) + # flag which colors are actually used during decompression + nb_colors = maximum(color) + color_used = zeros(Bool, nb_colors) + + # nonzero diagonal coefficients force the use of their respective color (there can be no neutral colors if the diagonal is fully nonzero) + if has_diagonal(g) + for i in axes(S, 1) + if !iszero(S[i, i]) + color_used[color[i]] = true + end + end + end + + if star_or_tree_set isa StarSet + # only the colors of the hubs are used + (; star, hub) = star_or_tree_set + nb_trivial_stars = 0 + + # Iterate through all non-trivial stars + for s in eachindex(hub) + h = hub[s] + if h > 0 + color_used[color[h]] = true + else + nb_trivial_stars += 1 + end + end + + # Process the trivial stars (if any) + if nb_trivial_stars > 0 + rvS = rowvals(S) + for j in axes(S, 2) + for k in nzrange(S, j) + i = rvS[k] + if i > j + index_ij = edge_to_index[k] + s = star[index_ij] + h = hub[s] + if h < 0 + h = abs(h) + spoke = h == j ? i : j + if color_used[color[spoke]] + # Switch the hub and the spoke to possibly avoid adding one more used color + hub[s] = spoke + else + # Keep the current hub + color_used[color[h]] = true + end + end + end + end + end + end + else + # only the colors of non-leaf vertices are used + (; reverse_bfs_orders, is_star, tree_edge_indices, nt) = star_or_tree_set + nb_trivial_trees = 0 + + # Iterate through all non-trivial trees + for k in 1:nt + # Position of the first edge in the tree + first = tree_edge_indices[k] + + # Total number of edges in the tree + ne_tree = tree_edge_indices[k + 1] - first + + # Check if we have more than one edge in the tree (non-trivial tree) + if ne_tree > 1 + # Determine if the tree is a star + if is_star[k] + # It is a non-trivial star and only the color of the hub is needed + (_, hub) = reverse_bfs_orders[first] + color_used[color[hub]] = true + else + # It is not a star and both colors are needed during the decompression + (i, j) = reverse_bfs_orders[first] + color_used[color[i]] = true + color_used[color[j]] = true + end + else + nb_trivial_trees += 1 + end + end + + # Process the trivial trees (if any) + if nb_trivial_trees > 0 + for k in 1:nt + # Position of the first edge in the tree + first = tree_edge_indices[k] + + # Total number of edges in the tree + ne_tree = tree_edge_indices[k + 1] - first + + # Check if we have exactly one edge in the tree + if ne_tree == 1 + (i, j) = reverse_bfs_orders[first] + if color_used[color[i]] + # Make i the root to avoid possibly adding one more used color + # Switch it with the (only) leaf + reverse_bfs_orders[first] = (j, i) + else + # Keep j as the root + color_used[color[j]] = true + end + end + end + end + end + + # if at least one of the colors is useless, modify the color assignments of vertices + if any(!, color_used) + num_colors_useless = 0 + + # determine what are the useless colors and compute the offsets + for ci in 1:nb_colors + if color_used[ci] + offsets[ci] = num_colors_useless + else + num_colors_useless += 1 + end + end + + # assign the neutral color to every vertex with a useless color and remap the colors + for i in eachindex(color) + ci = color[i] + if !color_used[ci] + # assign the neutral color + color[i] = 0 + else + # remap the color to not have any gap + color[i] -= offsets[ci] + end + end + end + return color +end