diff --git a/src/coloring.jl b/src/coloring.jl index 2746b30b..cf3d8f79 100644 --- a/src/coloring.jl +++ b/src/coloring.jl @@ -124,7 +124,7 @@ function star_coloring( for v in vertices_in_order for (w, index_vw) in neighbors_with_edge_indices(g, v) - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) color_w = color[w] iszero(color_w) && continue forbidden_colors[color_w] = v @@ -139,7 +139,7 @@ function star_coloring( else first_neighbor[color[w]] = (v, w, index_vw) for (x, index_wx) in neighbors_with_edge_indices(g, w) - !has_diagonal(g) || (w == x && continue) + augmented_graph(g) || (w == x && continue) color_x = color[x] (x == v || iszero(color_x)) && continue if x == hub[star[index_wx]] # potential Case 2 (which is always false for trivial stars with two vertices, since the associated hub is negative) @@ -184,7 +184,7 @@ function _treat!( color::AbstractVector{<:Integer}, ) for x in neighbors(g, w) - !has_diagonal(g) || (w == x && continue) + augmented_graph(g) || (w == x && continue) color_x = color[x] iszero(color_x) && continue forbidden_colors[color_x] = v @@ -204,12 +204,12 @@ function _update_stars!( first_neighbor::AbstractVector{<:Tuple}, ) for (w, index_vw) in neighbors_with_edge_indices(g, v) - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) color_w = color[w] iszero(color_w) && continue x_exists = false for (x, index_wx) in neighbors_with_edge_indices(g, w) - !has_diagonal(g) || (w == x && continue) + augmented_graph(g) || (w == x && continue) if x != v && color[x] == color[v] # vw, wx ∈ E star_wx = star[index_wx] hub[star_wx] = w # this may already be true @@ -286,16 +286,16 @@ function acyclic_coloring( for v in vertices_in_order for w in neighbors(g, v) - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) color_w = color[w] iszero(color_w) && continue forbidden_colors[color_w] = v end for w in neighbors(g, v) - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) iszero(color[w]) && continue for (x, index_wx) in neighbors_with_edge_indices(g, w) - !has_diagonal(g) || (w == x && continue) + augmented_graph(g) || (w == x && continue) color_x = color[x] iszero(color_x) && continue if forbidden_colors[color_x] != v @@ -320,16 +320,16 @@ function acyclic_coloring( end end for (w, index_vw) in neighbors_with_edge_indices(g, v) # grow two-colored stars around the vertex v - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) color_w = color[w] iszero(color_w) && continue _grow_star!(v, w, index_vw, color_w, first_neighbor, forest) end for (w, index_vw) in neighbors_with_edge_indices(g, v) - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) iszero(color[w]) && continue for (x, index_wx) in neighbors_with_edge_indices(g, w) - !has_diagonal(g) || (w == x && continue) + augmented_graph(g) || (w == x && continue) color_x = color[x] (x == v || iszero(color_x)) && continue if color_x == color[v] diff --git a/src/decompression.jl b/src/decompression.jl index a48c7e34..42bf51eb 100644 --- a/src/decompression.jl +++ b/src/decompression.jl @@ -547,7 +547,7 @@ function decompress!( end # Recover the diagonal coefficients of A - if has_diagonal(ag) + if !augmented_graph(ag) for i in axes(S, 1) if !iszero(S[i, i]) A[i, i] = B[i, color[i]] @@ -616,7 +616,7 @@ function decompress!( end # Recover the diagonal coefficients of A - if has_diagonal(ag) + if !augmented_graph(ag) if uplo == :L for i in diagonal_indices # A[i, i] is the first element in column i diff --git a/src/graph.jl b/src/graph.jl index 9b53a36d..84c3353f 100644 --- a/src/graph.jl +++ b/src/graph.jl @@ -202,7 +202,7 @@ end ## Adjacency graph """ - AdjacencyGraph{T,has_diagonal} + AdjacencyGraph{T,augmented_graph} Undirected graph without self-loops representing the nonzeros of a symmetric matrix (typically a Hessian matrix). @@ -213,18 +213,18 @@ The adjacency graph of a symmetric matrix `A ∈ ℝ^{n × n}` is `G(A) = (V, E) # Constructors - AdjacencyGraph(A::SparseMatrixCSC; has_diagonal::Bool=true) + AdjacencyGraph(A::SparseMatrixCSC; augmented_graph::Bool=false) # Fields -- `S::SparsityPatternCSC{T}`: Underlying sparsity pattern, whose diagonal is empty whenever `has_diagonal` is `false` +- `S::SparsityPatternCSC{T}`: Underlying sparsity pattern, which represents an augmented graph whenever `augmented_graph` is `true`. Here, "augmented graph" means the sparsity pattern of the augmented matrix `H = [0 Jᵀ; J 0]`. - `edge_to_index::Vector{T}`: A vector mapping each nonzero of `S` to a unique edge index (ignoring diagonal and accounting for symmetry, so that `(i, j)` and `(j, i)` get the same index) # References > [_What Color Is Your Jacobian? SparsityPatternCSC Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005) """ -struct AdjacencyGraph{T<:Integer,has_diagonal} +struct AdjacencyGraph{T<:Integer,augmented_graph} S::SparsityPatternCSC{T} edge_to_index::Vector{T} end @@ -234,24 +234,24 @@ Base.eltype(::AdjacencyGraph{T}) where {T} = T function AdjacencyGraph( S::SparsityPatternCSC{T}, edge_to_index::Vector{T}=build_edge_to_index(S); - has_diagonal::Bool=true, + augmented_graph::Bool=false, ) where {T} - return AdjacencyGraph{T,has_diagonal}(S, edge_to_index) + return AdjacencyGraph{T,augmented_graph}(S, edge_to_index) end -function AdjacencyGraph(A::SparseMatrixCSC; has_diagonal::Bool=true) - return AdjacencyGraph(SparsityPatternCSC(A); has_diagonal) +function AdjacencyGraph(A::SparseMatrixCSC; augmented_graph::Bool=false) + return AdjacencyGraph(SparsityPatternCSC(A); augmented_graph) end -function AdjacencyGraph(A::AbstractMatrix; has_diagonal::Bool=true) - return AdjacencyGraph(SparseMatrixCSC(A); has_diagonal) +function AdjacencyGraph(A::AbstractMatrix; augmented_graph::Bool=false) + return AdjacencyGraph(SparseMatrixCSC(A); augmented_graph) end pattern(g::AdjacencyGraph) = g.S edge_indices(g::AdjacencyGraph) = g.edge_to_index nb_vertices(g::AdjacencyGraph) = pattern(g).n vertices(g::AdjacencyGraph) = 1:nb_vertices(g) -has_diagonal(::AdjacencyGraph{T,hd}) where {T,hd} = hd +augmented_graph(::AdjacencyGraph{T,ag}) where {T,ag} = ag function neighbors(g::AdjacencyGraph, v::Integer) S = pattern(g) @@ -267,17 +267,17 @@ function neighbors_with_edge_indices(g::AdjacencyGraph, v::Integer) return zip(neighbors_v, edges_indices_v) end -degree(g::AdjacencyGraph{T,false}, v::Integer) where {T} = g.S.colptr[v + 1] - g.S.colptr[v] +degree(g::AdjacencyGraph{T,true}, v::Integer) where {T} = g.S.colptr[v + 1] - g.S.colptr[v] -function degree(g::AdjacencyGraph{T,true}, v::Integer) where {T} +function degree(g::AdjacencyGraph{T,false}, v::Integer) where {T} neigh = neighbors(g, v) has_selfloop = insorted(v, neigh) return g.S.colptr[v + 1] - g.S.colptr[v] - has_selfloop end -nb_edges(g::AdjacencyGraph{T,false}) where {T} = nnz(g.S) ÷ 2 +nb_edges(g::AdjacencyGraph{T,true}) where {T} = nnz(g.S) ÷ 2 -function nb_edges(g::AdjacencyGraph{T,true}) where {T} +function nb_edges(g::AdjacencyGraph{T,false}) where {T} ne = 0 for v in vertices(g) ne += degree(g, v) @@ -290,7 +290,7 @@ minimum_degree(g::AdjacencyGraph) = minimum(Base.Fix1(degree, g), vertices(g)) function has_neighbor(g::AdjacencyGraph, v::Integer, u::Integer) for w in neighbors(g, v) - !has_diagonal(g) || (v == w && continue) + augmented_graph(g) || (v == w && continue) if w == u return true end diff --git a/src/interface.jl b/src/interface.jl index b8d4ce54..cc57bcc7 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -279,7 +279,7 @@ function _coloring( symmetric_pattern::Bool; forced_colors::Union{AbstractVector{<:Integer},Nothing}=nothing, ) - ag = AdjacencyGraph(A; has_diagonal=true) + ag = AdjacencyGraph(A; augmented_graph=false) color_and_star_set_by_order = map(algo.orders) do order vertices_in_order = vertices(ag, order) return star_coloring(ag, vertices_in_order, algo.postprocessing; forced_colors) @@ -300,7 +300,7 @@ function _coloring( decompression_eltype::Type{R}, symmetric_pattern::Bool, ) where {R} - ag = AdjacencyGraph(A; has_diagonal=true) + ag = AdjacencyGraph(A; augmented_graph=false) color_and_tree_set_by_order = map(algo.orders) do order vertices_in_order = vertices(ag, order) return acyclic_coloring(ag, vertices_in_order, algo.postprocessing) @@ -323,7 +323,7 @@ function _coloring( forced_colors::Union{AbstractVector{<:Integer},Nothing}=nothing, ) where {R} A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern) - ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false) + ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; augmented_graph=true) outputs_by_order = map(algo.orders) do order vertices_in_order = vertices(ag, order) _color, _star_set = star_coloring( @@ -370,7 +370,7 @@ function _coloring( symmetric_pattern::Bool, ) where {R} A_and_Aᵀ, edge_to_index = bidirectional_pattern(A; symmetric_pattern) - ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; has_diagonal=false) + ag = AdjacencyGraph(A_and_Aᵀ, edge_to_index; augmented_graph=true) outputs_by_order = map(algo.orders) do order vertices_in_order = vertices(ag, order) _color, _tree_set = acyclic_coloring(ag, vertices_in_order, algo.postprocessing) diff --git a/src/order.jl b/src/order.jl index aab5bb23..20884c6a 100644 --- a/src/order.jl +++ b/src/order.jl @@ -334,7 +334,7 @@ function vertices( π[index] = u for v in neighbors(g, u) - !has_diagonal(g) || (u == v && continue) + augmented_graph(g) || (u == v && continue) dv = degrees[v] dv == -1 && continue update_bucket!(db, v, dv; degtype, direction) diff --git a/src/postprocessing.jl b/src/postprocessing.jl index 217b663b..8174d863 100644 --- a/src/postprocessing.jl +++ b/src/postprocessing.jl @@ -13,7 +13,7 @@ function postprocess!( 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) + if !augmented_graph(g) for i in axes(S, 1) if !iszero(S[i, i]) color_used[color[i]] = true diff --git a/src/result.jl b/src/result.jl index 7a3e3b68..89da22d6 100644 --- a/src/result.jl +++ b/src/result.jl @@ -411,7 +411,7 @@ function TreeSetColoringResult( diagonal_nzind = T[] ndiag = 0 - if has_diagonal(ag) + if !augmented_graph(ag) for j in axes(S, 2) for k in nzrange(S, j) i = rv[k] diff --git a/test/graph.jl b/test/graph.jl index 9c8f66c1..e9784e56 100644 --- a/test/graph.jl +++ b/test/graph.jl @@ -166,7 +166,7 @@ end; @test degree(g, 7) == 6 @test degree(g, 8) == 6 - g = AdjacencyGraph(transpose(A) * A; has_diagonal=false) + g = AdjacencyGraph(transpose(A) * A; augmented_graph=true) # wrong degree @test degree(g, 1) == 4 @test degree(g, 2) == 4 diff --git a/test/order.jl b/test/order.jl index 838c32a9..9cae16f1 100644 --- a/test/order.jl +++ b/test/order.jl @@ -61,16 +61,14 @@ end; end; @testset "LargestFirst" begin - for has_diagonal in (false, true) - A = sparse([ - 0 1 0 0 - 1 0 1 1 - 0 1 0 1 - 0 1 1 0 - ]) - ag = AdjacencyGraph(A; has_diagonal) - @test vertices(ag, LargestFirst()) == [2, 3, 4, 1] - end + A = sparse([ + 0 1 0 0 + 1 0 1 1 + 0 1 0 1 + 0 1 1 0 + ]) + ag = AdjacencyGraph(A) + @test vertices(ag, LargestFirst()) == [2, 3, 4, 1] A = sparse([ 1 1 0 0