Skip to content

Commit bedcd88

Browse files
committed
Allow picking the best of several orders for GreedyColoringAlgorithm
1 parent 7efc6bc commit bedcd88

2 files changed

Lines changed: 74 additions & 25 deletions

File tree

src/interface.jl

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ It is passed as an argument to the main function [`coloring`](@ref).
7272
GreedyColoringAlgorithm{decompression}(order=NaturalOrder(); postprocessing=false)
7373
GreedyColoringAlgorithm(order=NaturalOrder(); postprocessing=false, decompression=:direct)
7474
75-
- `order::AbstractOrder`: the order in which the columns or rows are colored, which can impact the number of colors.
75+
- `order::Union{AbstractOrder,NTuple}`: the order in which the columns or rows are colored, which can impact the number of colors. Can also be a tuple of different orders to try out, from which the best order (the one with the lowest total number of colors) will be used.
7676
- `postprocessing::Bool`: whether or not the coloring will be refined by assigning the neutral color `0` to some vertices.
7777
- `decompression::Symbol`: either `:direct` or `:substitution`. Usually `:substitution` leads to fewer colors, at the cost of a more expensive coloring (and decompression). When `:substitution` is not applicable, it falls back on `:direct` decompression.
7878
@@ -94,26 +94,31 @@ See their respective docstrings for details.
9494
- [`AbstractOrder`](@ref)
9595
- [`decompress`](@ref)
9696
"""
97-
struct GreedyColoringAlgorithm{decompression,O<:AbstractOrder} <:
97+
struct GreedyColoringAlgorithm{decompression,N,O<:NTuple{N,AbstractOrder}} <:
9898
ADTypes.AbstractColoringAlgorithm
99-
order::O
99+
orders::O
100100
postprocessing::Bool
101-
end
102101

103-
function GreedyColoringAlgorithm{decompression}(
104-
order::AbstractOrder=NaturalOrder(); postprocessing::Bool=false
105-
) where {decompression}
106-
check_valid_algorithm(decompression)
107-
return GreedyColoringAlgorithm{decompression,typeof(order)}(order, postprocessing)
102+
function GreedyColoringAlgorithm{decompression}(
103+
order_or_orders::Union{AbstractOrder,NTuple{N,AbstractOrder}}=NaturalOrder();
104+
postprocessing::Bool=false,
105+
) where {decompression,N}
106+
check_valid_algorithm(decompression)
107+
if order_or_orders isa AbstractOrder
108+
orders = (order_or_orders,)
109+
else
110+
orders = order_or_orders
111+
end
112+
return new{decompression,length(orders),typeof(orders)}(orders, postprocessing)
113+
end
108114
end
109115

110116
function GreedyColoringAlgorithm(
111-
order::AbstractOrder=NaturalOrder();
117+
order_or_orders::Union{AbstractOrder,NTuple{N,AbstractOrder}}=NaturalOrder();
112118
postprocessing::Bool=false,
113119
decompression::Symbol=:direct,
114-
)
115-
check_valid_algorithm(decompression)
116-
return GreedyColoringAlgorithm{decompression,typeof(order)}(order, postprocessing)
120+
) where {N}
121+
return GreedyColoringAlgorithm{decompression}(order_or_orders; postprocessing)
117122
end
118123

119124
## Coloring
@@ -229,8 +234,11 @@ function _coloring(
229234
)
230235
symmetric_pattern = symmetric_pattern || A isa Union{Symmetric,Hermitian}
231236
bg = BipartiteGraph(A; symmetric_pattern)
232-
vertices_in_order = vertices(bg, Val(2), algo.order)
233-
color = partial_distance2_coloring(bg, Val(2), vertices_in_order)
237+
color_by_order = map(algo.orders) do order
238+
vertices_in_order = vertices(bg, Val(2), order)
239+
return partial_distance2_coloring(bg, Val(2), vertices_in_order)
240+
end
241+
color = argmin(maximum, color_by_order)
234242
if speed_setting isa WithResult
235243
return ColumnColoringResult(A, bg, color)
236244
else
@@ -248,8 +256,11 @@ function _coloring(
248256
)
249257
symmetric_pattern = symmetric_pattern || A isa Union{Symmetric,Hermitian}
250258
bg = BipartiteGraph(A; symmetric_pattern)
251-
vertices_in_order = vertices(bg, Val(1), algo.order)
252-
color = partial_distance2_coloring(bg, Val(1), vertices_in_order)
259+
color_by_order = map(algo.orders) do order
260+
vertices_in_order = vertices(bg, Val(1), order)
261+
return partial_distance2_coloring(bg, Val(1), vertices_in_order)
262+
end
263+
color = argmin(maximum, color_by_order)
253264
if speed_setting isa WithResult
254265
return RowColoringResult(A, bg, color)
255266
else
@@ -266,8 +277,11 @@ function _coloring(
266277
symmetric_pattern::Bool,
267278
)
268279
ag = AdjacencyGraph(A; has_diagonal=true)
269-
vertices_in_order = vertices(ag, algo.order)
270-
color, star_set = star_coloring(ag, vertices_in_order, algo.postprocessing)
280+
color_and_star_set_by_order = map(algo.orders) do order
281+
vertices_in_order = vertices(ag, order)
282+
return star_coloring(ag, vertices_in_order, algo.postprocessing)
283+
end
284+
color, star_set = argmin(maximum first, color_and_star_set_by_order)
271285
if speed_setting isa WithResult
272286
return StarSetColoringResult(A, ag, color, star_set)
273287
else
@@ -284,8 +298,11 @@ function _coloring(
284298
symmetric_pattern::Bool,
285299
) where {R}
286300
ag = AdjacencyGraph(A; has_diagonal=true)
287-
vertices_in_order = vertices(ag, algo.order)
288-
color, tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
301+
color_and_tree_set_by_order = map(algo.orders) do order
302+
vertices_in_order = vertices(ag, order)
303+
return acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
304+
end
305+
color, tree_set = argmin(maximum first, color_and_tree_set_by_order)
289306
if speed_setting isa WithResult
290307
return TreeSetColoringResult(A, ag, color, tree_set, R)
291308
else
@@ -303,8 +320,11 @@ function _coloring(
303320
) where {R}
304321
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
305322
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
306-
vertices_in_order = vertices(ag, algo.order)
307-
color, star_set = star_coloring(ag, vertices_in_order, algo.postprocessing)
323+
color_and_star_set_by_order = map(algo.orders) do order
324+
vertices_in_order = vertices(ag, order)
325+
return star_coloring(ag, vertices_in_order, algo.postprocessing)
326+
end
327+
color, star_set = argmin(maximum first, color_and_star_set_by_order)
308328
if speed_setting isa WithResult
309329
symmetric_result = StarSetColoringResult(A_and_Aᵀ, ag, color, star_set)
310330
return BicoloringResult(A, ag, symmetric_result, R)
@@ -326,8 +346,11 @@ function _coloring(
326346
) where {R}
327347
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
328348
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
329-
vertices_in_order = vertices(ag, algo.order)
330-
color, tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
349+
color_and_tree_set_by_order = map(algo.orders) do order
350+
vertices_in_order = vertices(ag, order)
351+
return acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
352+
end
353+
color, tree_set = argmin(maximum first, color_and_tree_set_by_order)
331354
if speed_setting isa WithResult
332355
symmetric_result = TreeSetColoringResult(A_and_Aᵀ, ag, color, tree_set, R)
333356
return BicoloringResult(A, ag, symmetric_result, R)

test/utils.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ using SparseMatrixColorings:
1515
structurally_biorthogonal
1616
using Test
1717

18+
const _ALL_ORDERS = (
19+
NaturalOrder(), LargestFirst(), SmallestLast(), IncidenceDegree(), DynamicLargestFirst()
20+
)
21+
1822
function test_coloring_decompression(
1923
A0::AbstractMatrix,
2024
problem::ColoringProblem{structure,partition},
@@ -169,6 +173,17 @@ function test_coloring_decompression(
169173
@show color_vec
170174
end
171175
end
176+
177+
@testset "More orders is better" begin
178+
if algo.orders _ALL_ORDERS
179+
better_algo = GreedyColoringAlgorithm{decompression}(
180+
_ALL_ORDERS; algo.postprocessing
181+
)
182+
result = coloring(A0, problem, algo)
183+
better_result = coloring(A0, problem, better_algo)
184+
@test ncolors(result) >= ncolors(better_result)
185+
end
186+
end
172187
end
173188

174189
function test_bicoloring_decompression(
@@ -216,6 +231,17 @@ function test_bicoloring_decompression(
216231
end
217232
end
218233
end
234+
235+
@testset "More orders is better" begin
236+
if algo.orders _ALL_ORDERS
237+
better_algo = GreedyColoringAlgorithm{decompression}(
238+
_ALL_ORDERS; algo.postprocessing
239+
)
240+
result = coloring(A0, problem, algo)
241+
better_result = coloring(A0, problem, better_algo)
242+
@test ncolors(result) >= ncolors(better_result)
243+
end
244+
end
219245
end
220246

221247
function test_structured_coloring_decompression(A::AbstractMatrix)

0 commit comments

Comments
 (0)