Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SparseMatrixColorings"
uuid = "0a514795-09f3-496d-8182-132a7b665d35"
authors = ["Guillaume Dalle", "Alexis Montoison"]
version = "0.4.18"
version = "0.4.19"

[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Expand Down
25 changes: 11 additions & 14 deletions src/coloring.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""
partial_distance2_coloring(bg::BipartiteGraph, ::Val{side}, order::AbstractOrder)
partial_distance2_coloring(bg::BipartiteGraph, ::Val{side}, vertices_in_order::AbstractVector)

Compute a distance-2 coloring of the given `side` (`1` or `2`) in the bipartite graph `bg` and return a vector of integer colors.

A _distance-2 coloring_ is such that two vertices have different colors if they are at distance at most 2.

The vertices are colored in a greedy fashion, following the `order` supplied.
The vertices are colored in a greedy fashion, following the order supplied.

# See also

Expand All @@ -17,11 +17,10 @@ The vertices are colored in a greedy fashion, following the `order` supplied.
> [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005), Algorithm 3.2
"""
function partial_distance2_coloring(
bg::BipartiteGraph{T}, ::Val{side}, order::AbstractOrder
bg::BipartiteGraph{T}, ::Val{side}, vertices_in_order::AbstractVector{<:Integer}
) where {T,side}
color = Vector{T}(undef, nb_vertices(bg, Val(side)))
forbidden_colors = Vector{T}(undef, nb_vertices(bg, Val(side)))
vertices_in_order = vertices(bg, Val(side), order)
partial_distance2_coloring!(color, forbidden_colors, bg, Val(side), vertices_in_order)
return color
end
Expand Down Expand Up @@ -54,7 +53,7 @@ function partial_distance2_coloring!(
end

"""
star_coloring(g::AdjacencyGraph, order::AbstractOrder, postprocessing::Bool)
star_coloring(g::AdjacencyGraph, vertices_in_order::AbstractVector, postprocessing::Bool)

Compute a star coloring of all vertices in the adjacency graph `g` and return a tuple `(color, star_set)`, where

Expand All @@ -63,7 +62,7 @@ Compute a star coloring of all vertices in the adjacency graph `g` and return a

A _star coloring_ is a distance-1 coloring such that every path on 4 vertices uses at least 3 colors.

The vertices are colored in a greedy fashion, following the `order` supplied.
The vertices are colored in a greedy fashion, following the order supplied.

If `postprocessing=true`, some colors might be replaced with `0` (the "neutral" color) as long as they are not needed during decompression.

Expand All @@ -77,7 +76,7 @@ If `postprocessing=true`, some colors might be replaced with `0` (the "neutral"
> [_New Acyclic and Star Coloring Algorithms with Application to Computing Hessians_](https://epubs.siam.org/doi/abs/10.1137/050639879), Gebremedhin et al. (2007), Algorithm 4.1
"""
function star_coloring(
g::AdjacencyGraph{T}, order::AbstractOrder, postprocessing::Bool
g::AdjacencyGraph{T}, vertices_in_order::AbstractVector{<:Integer}, postprocessing::Bool
) where {T<:Integer}
# Initialize data structures
nv = nb_vertices(g)
Expand All @@ -88,7 +87,6 @@ function star_coloring(
treated = zeros(T, nv)
star = Vector{T}(undef, ne)
hub = T[] # one hub for each star, including the trivial ones
vertices_in_order = vertices(g, order)

for v in vertices_in_order
for (w, index_vw) in neighbors_with_edge_indices(g, v)
Expand Down Expand Up @@ -206,7 +204,7 @@ struct StarSet{T}
end

"""
acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder, postprocessing::Bool)
acyclic_coloring(g::AdjacencyGraph, vertices_in_order::AbstractVector, postprocessing::Bool)

Compute an acyclic coloring of all vertices in the adjacency graph `g` and return a tuple `(color, tree_set)`, where

Expand All @@ -215,7 +213,7 @@ Compute an acyclic coloring of all vertices in the adjacency graph `g` and retur

An _acyclic coloring_ is a distance-1 coloring with the further restriction that every cycle uses at least 3 colors.

The vertices are colored in a greedy fashion, following the `order` supplied.
The vertices are colored in a greedy fashion, following the order supplied.

If `postprocessing=true`, some colors might be replaced with `0` (the "neutral" color) as long as they are not needed during decompression.

Expand All @@ -229,7 +227,7 @@ If `postprocessing=true`, some colors might be replaced with `0` (the "neutral"
> [_New Acyclic and Star Coloring Algorithms with Application to Computing Hessians_](https://epubs.siam.org/doi/abs/10.1137/050639879), Gebremedhin et al. (2007), Algorithm 3.1
"""
function acyclic_coloring(
g::AdjacencyGraph{T}, order::AbstractOrder, postprocessing::Bool
g::AdjacencyGraph{T}, vertices_in_order::AbstractVector{<:Integer}, postprocessing::Bool
) where {T<:Integer}
# Initialize data structures
nv = nb_vertices(g)
Expand All @@ -239,7 +237,6 @@ function acyclic_coloring(
first_neighbor = fill((zero(T), zero(T), zero(T)), nv) # at first no neighbors have been encountered
first_visit_to_tree = fill((zero(T), zero(T)), ne)
forest = Forest{T}(ne)
vertices_in_order = vertices(g, order)

for v in vertices_in_order
for w in neighbors(g, v)
Expand Down Expand Up @@ -527,8 +524,8 @@ function TreeSet(
# Positions of the first and last vertices in the current tree
# Note: tree_edge_indices contains the positions of the first and last edges,
# so we add to add an offset k-1 between edge indices and vertex indices
first_vertex = tree_edge_indices[k] + (k-1)
last_vertex = tree_edge_indices[k + 1] + (k-1)
first_vertex = tree_edge_indices[k] + (k - 1)
last_vertex = tree_edge_indices[k + 1] + (k - 1)

# compute the degree of each vertex in the tree
for index_vertex in first_vertex:last_vertex
Expand Down
28 changes: 16 additions & 12 deletions src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@ function _coloring(
decompression_eltype::Type,
symmetric_pattern::Bool,
)
bg = BipartiteGraph(
A; symmetric_pattern=symmetric_pattern || A isa Union{Symmetric,Hermitian}
)
color = partial_distance2_coloring(bg, Val(2), algo.order)
symmetric_pattern = symmetric_pattern || A isa Union{Symmetric,Hermitian}
bg = BipartiteGraph(A; symmetric_pattern)
vertices_in_order = vertices(bg, Val(2), algo.order)
color = partial_distance2_coloring(bg, Val(2), vertices_in_order)
if speed_setting isa WithResult
return ColumnColoringResult(A, bg, color)
else
Expand All @@ -246,10 +246,10 @@ function _coloring(
decompression_eltype::Type,
symmetric_pattern::Bool,
)
bg = BipartiteGraph(
A; symmetric_pattern=symmetric_pattern || A isa Union{Symmetric,Hermitian}
)
color = partial_distance2_coloring(bg, Val(1), algo.order)
symmetric_pattern = symmetric_pattern || A isa Union{Symmetric,Hermitian}
bg = BipartiteGraph(A; symmetric_pattern)
vertices_in_order = vertices(bg, Val(1), algo.order)
color = partial_distance2_coloring(bg, Val(1), vertices_in_order)
if speed_setting isa WithResult
return RowColoringResult(A, bg, color)
else
Expand All @@ -266,7 +266,8 @@ function _coloring(
symmetric_pattern::Bool,
)
ag = AdjacencyGraph(A; has_diagonal=true)
color, star_set = star_coloring(ag, algo.order, algo.postprocessing)
vertices_in_order = vertices(ag, algo.order)
color, star_set = star_coloring(ag, vertices_in_order, algo.postprocessing)
if speed_setting isa WithResult
return StarSetColoringResult(A, ag, color, star_set)
else
Expand All @@ -283,7 +284,8 @@ function _coloring(
symmetric_pattern::Bool,
) where {R}
ag = AdjacencyGraph(A; has_diagonal=true)
color, tree_set = acyclic_coloring(ag, algo.order, algo.postprocessing)
vertices_in_order = vertices(ag, algo.order)
color, tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
if speed_setting isa WithResult
return TreeSetColoringResult(A, ag, color, tree_set, R)
else
Expand All @@ -301,7 +303,8 @@ function _coloring(
) where {R}
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
color, star_set = star_coloring(ag, algo.order, algo.postprocessing)
vertices_in_order = vertices(ag, algo.order)
color, star_set = star_coloring(ag, vertices_in_order, algo.postprocessing)
if speed_setting isa WithResult
symmetric_result = StarSetColoringResult(A_and_Aᵀ, ag, color, star_set)
return BicoloringResult(A, ag, symmetric_result, R)
Expand All @@ -323,7 +326,8 @@ function _coloring(
) where {R}
A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern)
ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false)
color, tree_set = acyclic_coloring(ag, algo.order, algo.postprocessing)
vertices_in_order = vertices(ag, algo.order)
color, tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing)
if speed_setting isa WithResult
symmetric_result = TreeSetColoringResult(A_and_Aᵀ, ag, color, tree_set, R)
return BicoloringResult(A, ag, symmetric_result, R)
Expand Down
46 changes: 29 additions & 17 deletions test/suitesparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ using Test

nbunique(x) = length(unique(x))

_N() = NaturalOrder()
_LF() = LargestFirst()
_SL() = SmallestLast(; reproduce_colpack=true)
_ID() = IncidenceDegree(; reproduce_colpack=true)
_DLF() = DynamicLargestFirst(; reproduce_colpack=true)
_N(args...) = vertices(args..., NaturalOrder())
_LF(args...) = vertices(args..., LargestFirst())
_SL(args...) = vertices(args..., SmallestLast(; reproduce_colpack=true))
_ID(args...) = vertices(args..., IncidenceDegree(; reproduce_colpack=true))
_DLF(args...) = vertices(args..., DynamicLargestFirst(; reproduce_colpack=true))

## Distance-2 coloring

Expand All @@ -49,13 +49,17 @@ colpack_table_6_7 = CSV.read(
@test maximum_degree(bg, Val(2)) == row[:Δ2]
end
@testset "Natural" begin
@test nbunique(partial_distance2_coloring(bg, Val(1), _N())) == row[:N1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _N())) == row[:N2]
@test nbunique(partial_distance2_coloring(bg, Val(1), _N(bg, Val(1)))) ==
row[:N1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _N(bg, Val(2)))) ==
row[:N2]
end
yield()
@testset "LargestFirst" begin
@test nbunique(partial_distance2_coloring(bg, Val(1), _LF())) == row[:LF1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _LF())) == row[:LF2]
@test nbunique(partial_distance2_coloring(bg, Val(1), _LF(bg, Val(1)))) ==
row[:LF1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _LF(bg, Val(2)))) ==
row[:LF2]
end
yield()
if row[:name] == "af23560"
Expand All @@ -67,18 +71,24 @@ colpack_table_6_7 = CSV.read(
continue
end
@testset "SmallestLast" begin
@test nbunique(partial_distance2_coloring(bg, Val(1), _SL())) == row[:SL1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _SL())) == row[:SL2]
@test nbunique(partial_distance2_coloring(bg, Val(1), _SL(bg, Val(1)))) ==
row[:SL1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _SL(bg, Val(2)))) ==
row[:SL2]
end
yield()
@testset "IncidenceDegree" begin
@test nbunique(partial_distance2_coloring(bg, Val(1), _ID())) == row[:ID1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _ID())) == row[:ID2]
@test nbunique(partial_distance2_coloring(bg, Val(1), _ID(bg, Val(1)))) ==
row[:ID1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _ID(bg, Val(2)))) ==
row[:ID2]
end
yield()
@testset "DynamicLargestFirst" begin
@test nbunique(partial_distance2_coloring(bg, Val(1), _DLF())) == row[:DLF1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _DLF())) == row[:DLF2]
@test nbunique(partial_distance2_coloring(bg, Val(1), _DLF(bg, Val(1)))) ==
row[:DLF1]
@test nbunique(partial_distance2_coloring(bg, Val(2), _DLF(bg, Val(2)))) ==
row[:DLF2]
end
yield()
end
Expand All @@ -105,7 +115,8 @@ what_table_31_32 = CSV.read(
@test maximum_degree(bg, Val(1)) == row[:ρmax]
@test minimum_degree(bg, Val(2)) == row[:κmin]
@test maximum_degree(bg, Val(2)) == row[:κmax]
color_Nb = partial_distance2_coloring(bg, Val(2), NaturalOrder())
vertices_in_order = vertices(bg, Val(2), NaturalOrder())
color_Nb = partial_distance2_coloring(bg, Val(2), vertices_in_order)
if length(unique(color_Nb)) == row[:K]
@test length(unique(color_Nb)) == row[:K]
else
Expand Down Expand Up @@ -133,7 +144,8 @@ what_table_41_42 = CSV.read(
@test maximum_degree(ag) == row[:Δ]
@test minimum_degree(ag) == row[:δ]
postprocessing = false
color_N, _ = star_coloring(ag, NaturalOrder(), postprocessing)
vertices_in_order = vertices(ag, NaturalOrder())
color_N, _ = star_coloring(ag, vertices_in_order, postprocessing)
@test_skip row[:KS1] <= length(unique(color_N)) <= row[:KS2] # TODO: find better
yield()
end
Expand Down