From 1fa90cb4dc49ba1ac5a92b7a4c22cacda74d277f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 16 Oct 2026 12:18:10 +0200 Subject: [PATCH] Handle empty symmetric coloring patterns --- src/interface.jl | 10 ++-------- src/postprocessing.jl | 2 +- test/empty.jl | 34 ++++++++++++++++++++++++++++++++++ test/runtests.jl | 3 +++ 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 test/empty.jl diff --git a/src/interface.jl b/src/interface.jl index 6b42523a..bc6b404b 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -313,7 +313,7 @@ function _coloring( vertices_in_order = vertices(ag, order) return star_coloring(ag, vertices_in_order, algo.postprocessing; forced_colors) end - color, star_set = argmin(maximum ∘ first, color_and_star_set_by_order) + color, star_set = argmin(t -> maximum(first(t); init=0), color_and_star_set_by_order) if speed_setting isa WithResult return StarSetColoringResult(A, ag, color, star_set) else @@ -334,13 +334,7 @@ function _coloring( vertices_in_order = vertices(ag, order) return acyclic_coloring(ag, vertices_in_order, algo.postprocessing) end - # if `color` is empty, `maximum` will fail but `color_and_tree_set_by_order` - # is also one so we can just add a special case for this - if length(color_and_tree_set_by_order) == 1 - color, tree_set = only(color_and_tree_set_by_order) - else - color, tree_set = argmin(maximum ∘ first, color_and_tree_set_by_order) - end + color, tree_set = argmin(t -> maximum(first(t); init=0), color_and_tree_set_by_order) if speed_setting isa WithResult return TreeSetColoringResult(A, ag, color, tree_set, R) else diff --git a/src/postprocessing.jl b/src/postprocessing.jl index a6a445a5..4c2a5f01 100644 --- a/src/postprocessing.jl +++ b/src/postprocessing.jl @@ -8,7 +8,7 @@ function postprocess!( postprocessing_minimizes::Symbol, ) # flag which colors are actually used during decompression - nb_colors = maximum(color) + nb_colors = maximum(color; init=0) 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) diff --git a/test/empty.jl b/test/empty.jl new file mode 100644 index 00000000..6dfe175b --- /dev/null +++ b/test/empty.jl @@ -0,0 +1,34 @@ +using LinearAlgebra +using SparseArrays +using SparseMatrixColorings +using Test + +@testset "Empty symmetric coloring" begin + problem = ColoringProblem(; structure=:symmetric, partition=:column) + orders = (NaturalOrder(), LargestFirst(), (NaturalOrder(), LargestFirst())) + matrices = ( + zeros(0, 0), + spzeros(0, 0), + Symmetric(spzeros(0, 0)), + SparseMatrixColorings.SparsityPatternCSC(spzeros(0, 0)), + ) + @testset "$decompression, $postprocessing, $order, $(typeof(A))" for decompression in ( + :direct, :substitution + ), + postprocessing in (false, true), order in orders, + A in matrices + + algo = GreedyColoringAlgorithm(order; decompression, postprocessing) + result = coloring(A, problem, algo) + @test ncolors(result) == 0 + @test isempty(column_colors(result)) + @test isempty(column_groups(result)) + @test fast_coloring(A, problem, algo) == Int[] + B = compress(A, result) + @test size(B) == (0, 0) + @test decompress(B, result) == A + target = spzeros(0, 0) + @test decompress!(target, B, result) === target + @test size(target) == (0, 0) + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 877ebbbe..1faea11c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -72,6 +72,9 @@ using Colors: Colors end end @testset verbose = true "Correctness" begin + @testset "Empty matrices" begin + include("empty.jl") + end @testset "Small instances" begin include("small.jl") end