diff --git a/.gitignore b/.gitignore index 54d19120..92aecb9f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +playground.jl + *.json *.json.tmp diff --git a/docs/src/dev.md b/docs/src/dev.md index 18f8a48d..b8aa2792 100644 --- a/docs/src/dev.md +++ b/docs/src/dev.md @@ -10,12 +10,11 @@ The docstrings on this page describe internals, they are not part of the public ## Graph storage ```@docs -SparseMatrixColorings.Graph +SparseMatrixColorings.SparsityPatternCSC +SparseMatrixColorings.AdjacencyGraph SparseMatrixColorings.BipartiteGraph SparseMatrixColorings.vertices SparseMatrixColorings.neighbors -SparseMatrixColorings.adjacency_graph -SparseMatrixColorings.bipartite_graph transpose ``` diff --git a/src/coloring.jl b/src/coloring.jl index e470bb90..d5b3b08f 100644 --- a/src/coloring.jl +++ b/src/coloring.jl @@ -54,7 +54,7 @@ function partial_distance2_coloring!( end """ - star_coloring(g::Graph, order::AbstractOrder) + star_coloring(g::AdjacencyGraph, order::AbstractOrder) Compute a star coloring of all vertices in the adjacency graph `g` and return a tuple `(color, star_set)`, where @@ -67,14 +67,14 @@ The vertices are colored in a greedy fashion, following the `order` supplied. # See also -- [`Graph`](@ref) +- [`AdjacencyGraph`](@ref) - [`AbstractOrder`](@ref) # References > [_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::Graph{false}, order::AbstractOrder) +function star_coloring(g::AdjacencyGraph, order::AbstractOrder) # Initialize data structures nv = nb_vertices(g) color = zeros(Int, nv) @@ -157,7 +157,7 @@ function _treat!( treated::AbstractVector{<:Integer}, forbidden_colors::AbstractVector{<:Integer}, # not modified - g::Graph, + g::AdjacencyGraph, v::Integer, w::Integer, color::AbstractVector{<:Integer}, @@ -175,7 +175,7 @@ function _update_stars!( star::Dict{<:Tuple,<:Integer}, hub::AbstractVector{<:Integer}, # not modified - g::Graph, + g::AdjacencyGraph, v::Integer, color::AbstractVector{<:Integer}, first_neighbor::AbstractVector{<:Tuple}, @@ -247,7 +247,7 @@ function symmetric_coefficient( end """ - acyclic_coloring(g::Graph, order::AbstractOrder) + acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder) Compute an acyclic coloring of all vertices in the adjacency graph `g` and return a tuple `(color, tree_set)`, where @@ -260,17 +260,17 @@ The vertices are colored in a greedy fashion, following the `order` supplied. # See also -- [`Graph`](@ref) +- [`AdjacencyGraph`](@ref) - [`AbstractOrder`](@ref) # References > [_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::Graph{false}, order::AbstractOrder) +function acyclic_coloring(g::AdjacencyGraph, order::AbstractOrder) # Initialize data structures nv = nb_vertices(g) - ne = nb_edges(g) ÷ 2 # symmetric sparse matrix with empty diagonal + ne = nb_edges(g) color = zeros(Int, nv) forbidden_colors = zeros(Int, nv) first_neighbor = fill((0, 0), nv) # at first no neighbors have been encountered diff --git a/src/graph.jl b/src/graph.jl index fc26a80d..9d13b827 100644 --- a/src/graph.jl +++ b/src/graph.jl @@ -1,14 +1,9 @@ ## Standard graph """ - Graph{loops,T} + SparsityPatternCSC{Ti<:Integer} Store a sparse matrix (in CSC) without its values, keeping only the pattern of nonzeros. -It can be seen as a graph mapping columns to rows, hence the name `Graph`. - -The type parameter `loops` must be set to: -- `true` if coefficients `(i, i)` present in the CSC are counted as edges in the graph (e.g. for each half of a bipartite graph) -- `false` otherwise (e.g. for an adjacency graph) # Fields @@ -16,79 +11,33 @@ Copied from `SparseMatrixCSC`: - `m::Int`: number of rows - `n::Int`: number of columns -- `colptr::Vector{T}`: column `j` is in `colptr[j]:(colptr[j+1]-1)` -- `rowval::Vector{T}`: row indices of stored values +- `colptr::Vector{Ti}`: column `j` is in `colptr[j]:(colptr[j+1]-1)` +- `rowval::Vector{Ti}`: row indices of stored values """ -struct Graph{loops,T<:Integer} +struct SparsityPatternCSC{Ti<:Integer} m::Int n::Int - colptr::Vector{T} - rowval::Vector{T} -end - -function Graph{loops}(S::SparseMatrixCSC{Tv,Ti}) where {loops,Tv,Ti} - return Graph{loops,Ti}(S.m, S.n, S.colptr, S.rowval) -end - -Base.size(g::Graph) = (g.m, g.n) -SparseArrays.nnz(g::Graph) = length(g.rowval) -SparseArrays.rowvals(g::Graph) = g.rowval -SparseArrays.nzrange(g::Graph, j::Integer) = g.colptr[j]:(g.colptr[j + 1] - 1) - -nb_vertices(g::Graph) = g.n -vertices(g::Graph) = 1:nb_vertices(g) - -nb_edges(g::Graph{true}) = length(g.rowval) - -function nb_edges(g::Graph{false}) - ne = 0 - for j in vertices(g) - for k in nzrange(g, j) - i = rowvals(g)[k] - if i != j - ne += 1 - end - end - end - return ne + colptr::Vector{Ti} + rowval::Vector{Ti} end -function neighbors(g::Graph{true}, v::Integer) - return view(rowvals(g), nzrange(g, v)) -end - -function neighbors(g::Graph{false}, v::Integer) - neighbors_with_loops = view(rowvals(g), nzrange(g, v)) - return Iterators.filter(!=(v), neighbors_with_loops) # TODO: optimize -end +SparsityPatternCSC(A::SparseMatrixCSC) = SparsityPatternCSC(A.m, A.n, A.colptr, A.rowval) -function degree(g::Graph{true}, v::Integer) - return length(nzrange(g, v)) -end - -function degree(g::Graph{false}, v::Integer) - d = length(nzrange(g, v)) - for k in nzrange(g, v) - if rowvals(g)[k] == v - d -= 1 - end - end - return d -end - -maximum_degree(g::Graph) = maximum(Base.Fix1(degree, g), vertices(g)) -minimum_degree(g::Graph) = minimum(Base.Fix1(degree, g), vertices(g)) +Base.size(S::SparsityPatternCSC) = (S.m, S.n) +SparseArrays.nnz(S::SparsityPatternCSC) = length(S.rowval) +SparseArrays.rowvals(S::SparsityPatternCSC) = S.rowval +SparseArrays.nzrange(S::SparsityPatternCSC, j::Integer) = S.colptr[j]:(S.colptr[j + 1] - 1) """ - transpose(g::Graph) + transpose(S::SparsityPatternCSC) -Return a [`Graph`](@ref) corresponding to the transpose of (the underlying matrix of) `g`. +Return a [`SparsityPatternCSC`](@ref) corresponding to the transpose of `S`. """ -function Base.transpose(g::Graph{loops,T}) where {loops,T} - m, n = size(g) - nnzA = nnz(g) - A_colptr = g.colptr - A_rowval = g.rowval +function Base.transpose(S::SparsityPatternCSC{T}) where {T} + m, n = size(S) + nnzA = nnz(S) + A_colptr = S.colptr + A_rowval = S.rowval # Allocate storage for the column pointers and row indices of B = Aᵀ B_colptr = zeros(T, m + 1) @@ -129,32 +78,128 @@ function Base.transpose(g::Graph{loops,T}) where {loops,T} end B_colptr[1] = 1 - return Graph{loops,T}(n, m, B_colptr, B_rowval) + return SparsityPatternCSC{T}(n, m, B_colptr, B_rowval) +end + +## Adjacency graph + +""" + AdjacencyGraph{T} + +Undirected graph without self-loops representing the nonzeros of a symmetric matrix (typically a Hessian matrix). + +The adjacency graph of a symmetrix matric `A ∈ ℝ^{n × n}` is `G(A) = (V, E)` where + +- `V = 1:n` is the set of rows or columns `i`/`j` +- `(i, j) ∈ E` whenever `A[i, j] ≠ 0` and `i ≠ j` + +# Constructors + + AdjacencyGraph(A::SparseMatrixCSC) + +# Fields + +- `S::SparsityPatternCSC{T}` + +# 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} + S::SparsityPatternCSC{T} +end + +AdjacencyGraph(A::SparseMatrixCSC) = AdjacencyGraph(SparsityPatternCSC(A)) + +pattern(g::AdjacencyGraph) = g.S +nb_vertices(g::AdjacencyGraph) = pattern(g).n +vertices(g::AdjacencyGraph) = 1:nb_vertices(g) + +function neighbors(g::AdjacencyGraph, v::Integer) + S = pattern(g) + neighbors_with_loops = view(rowvals(S), nzrange(S, v)) + return Iterators.filter(!=(v), neighbors_with_loops) # TODO: optimize +end + +function degree(g::AdjacencyGraph, v::Integer) + d = 0 + for u in neighbors(g, v) + if u != v + d += 1 + end + end + return d +end + +function nb_edges(g::AdjacencyGraph) + S = pattern(g) + ne = 0 + for j in vertices(g) + for k in nzrange(S, j) + i = rowvals(S)[k] + if i > j + ne += 1 + end + end + end + return ne end +maximum_degree(g::AdjacencyGraph) = maximum(Base.Fix1(degree, g), vertices(g)) +minimum_degree(g::AdjacencyGraph) = minimum(Base.Fix1(degree, g), vertices(g)) + ## Bipartite graph """ BipartiteGraph{T} -Undirected bipartite graph structure stored in bidirectional Compressed Sparse Column format (redundancy allows for faster access). +Undirected bipartite graph representing the nonzeros of a non-symmetric matrix (typically a Jacobian matrix). + +The bipartite graph of a matrix `A ∈ ℝ^{m × n}` is `Gb(A) = (V₁, V₂, E)` where -A bipartite graph has two "sides", which we number `1` and `2`. +- `V₁ = 1:m` is the set of rows `i` +- `V₂ = 1:n` is the set of columns `j` +- `(i, j) ∈ E` whenever `A[i, j] ≠ 0` + +A `BipartiteGraph` has two sets of vertices, one for the rows of `A` (which we call side `1`) and one for the columns (which we call side `2`). + +# Constructors + + BipartiteGraph(A::SparseMatrixCSC; symmetric_pattern=false) + +When `symmetric_pattern` is `true`, this construction is more efficient. # Fields -- `g1::Graph{T}`: contains the neighbors for vertices on side `1` -- `g2::Graph{T}`: contains the neighbors for vertices on side `2` +- `S1::SparsityPatternCSC{T}`: maps vertices on side `1` to their neighbors +- `S2::SparsityPatternCSC{T}`: maps vertices on side `2` to their neighbors + +# References + +> [_What Color Is Your Jacobian? SparsityPatternCSC Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005) """ struct BipartiteGraph{T<:Integer} - g1::Graph{true,T} - g2::Graph{true,T} + S1::SparsityPatternCSC{T} + S2::SparsityPatternCSC{T} end -nb_vertices(bg::BipartiteGraph, ::Val{1}) = nb_vertices(bg.g1) -nb_vertices(bg::BipartiteGraph, ::Val{2}) = nb_vertices(bg.g2) +function BipartiteGraph(A::SparseMatrixCSC; symmetric_pattern::Bool=false) + S2 = SparsityPatternCSC(A) # columns to rows + if symmetric_pattern + checksquare(A) # proxy for checking full symmetry + S1 = S2 + else + S1 = transpose(S2) # rows to columns + end + return BipartiteGraph(S1, S2) +end -nb_edges(bg::BipartiteGraph) = nb_edges(bg.g1) +pattern(bg::BipartiteGraph, ::Val{1}) = bg.S1 +pattern(bg::BipartiteGraph, ::Val{2}) = bg.S2 + +nb_vertices(bg::BipartiteGraph, ::Val{side}) where {side} = pattern(bg, Val(side)).n + +nb_edges(bg::BipartiteGraph) = nnz(pattern(bg, Val(1))) """ vertices(bg::BipartiteGraph, Val(side)) @@ -168,11 +213,14 @@ vertices(bg::BipartiteGraph, ::Val{side}) where {side} = 1:nb_vertices(bg, Val(s Return the neighbors of `v` (a vertex from the specified `side`, `1` or `2`), in the graph `bg`. """ -neighbors(bg::BipartiteGraph, ::Val{1}, v::Integer) = neighbors(bg.g1, v) -neighbors(bg::BipartiteGraph, ::Val{2}, v::Integer) = neighbors(bg.g2, v) +function neighbors(bg::BipartiteGraph, ::Val{side}, v::Integer) where {side} + S = pattern(bg, Val(side)) + return view(rowvals(S), nzrange(S, v)) +end -degree(bg::BipartiteGraph, ::Val{1}, v::Integer) = degree(bg.g1, v) -degree(bg::BipartiteGraph, ::Val{2}, v::Integer) = degree(bg.g2, v) +function degree(bg::BipartiteGraph, ::Val{side}, v::Integer) where {side} + return length(neighbors(bg, Val(side), v)) +end function maximum_degree(bg::BipartiteGraph, ::Val{side}) where {side} return maximum(v -> degree(bg, Val(side), v), vertices(bg, Val(side))) @@ -193,49 +241,3 @@ function degree_dist2(bg::BipartiteGraph{T}, ::Val{side}, v::Integer) where {T,s end return length(neighbors_dist2) end - -## Construct from matrices - -""" - adjacency_graph(A::SparseMatrixCSC) - -Return a [`Graph`](@ref) representing the nonzeros of a symmetric matrix (typically a Hessian matrix). - -The adjacency graph of a symmetrix matric `A ∈ ℝ^{n × n}` is `G(A) = (V, E)` where - -- `V = 1:n` is the set of rows or columns `i`/`j` -- `(i, j) ∈ E` whenever `A[i, j] ≠ 0` and `i ≠ j` - -# References - -> [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005) -""" -adjacency_graph(A::SparseMatrixCSC) = Graph{false}(A) - -""" - bipartite_graph(A::SparseMatrixCSC; symmetric_pattern::Bool) - -Return a [`BipartiteGraph`](@ref) representing the nonzeros of a non-symmetric matrix (typically a Jacobian matrix). - -The bipartite graph of a matrix `A ∈ ℝ^{m × n}` is `Gb(A) = (V₁, V₂, E)` where - -- `V₁ = 1:m` is the set of rows `i` -- `V₂ = 1:n` is the set of columns `j` -- `(i, j) ∈ E` whenever `A[i, j] ≠ 0` - -When `symmetric_pattern` is `true`, this construction is more efficient. - -# References - -> [_What Color Is Your Jacobian? Graph Coloring for Computing Derivatives_](https://epubs.siam.org/doi/10.1137/S0036144504444711), Gebremedhin et al. (2005) -""" -function bipartite_graph(A::SparseMatrixCSC; symmetric_pattern::Bool=false) - g2 = Graph{true}(A) # columns to rows - if symmetric_pattern - checksquare(A) # proxy for checking full symmetry - g1 = g2 - else - g1 = transpose(g2) # rows to columns - end - return BipartiteGraph(g1, g2) -end diff --git a/src/interface.jl b/src/interface.jl index 495dfccf..5a559ffc 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -181,7 +181,7 @@ function coloring( symmetric_pattern::Bool=false, ) S = convert(SparseMatrixCSC, A) - bg = bipartite_graph( + bg = BipartiteGraph( S; symmetric_pattern=symmetric_pattern || A isa Union{Symmetric,Hermitian} ) color = partial_distance2_coloring(bg, Val(2), algo.order) @@ -196,7 +196,7 @@ function coloring( symmetric_pattern::Bool=false, ) S = convert(SparseMatrixCSC, A) - bg = bipartite_graph( + bg = BipartiteGraph( S; symmetric_pattern=symmetric_pattern || A isa Union{Symmetric,Hermitian} ) color = partial_distance2_coloring(bg, Val(1), algo.order) @@ -210,7 +210,7 @@ function coloring( decompression_eltype::Type=Float64, ) S = convert(SparseMatrixCSC, A) - ag = adjacency_graph(S) + ag = AdjacencyGraph(S) color, star_set = star_coloring(ag, algo.order) return StarSetColoringResult(S, color, star_set) end @@ -222,7 +222,7 @@ function coloring( decompression_eltype::Type=Float64, ) S = convert(SparseMatrixCSC, A) - ag = adjacency_graph(S) + ag = AdjacencyGraph(S) color, tree_set = acyclic_coloring(ag, algo.order) return TreeSetColoringResult(S, color, tree_set, decompression_eltype) end @@ -231,21 +231,21 @@ end function ADTypes.column_coloring(A::AbstractMatrix, algo::GreedyColoringAlgorithm) S = convert(SparseMatrixCSC, A) - bg = bipartite_graph(S; symmetric_pattern=A isa Union{Symmetric,Hermitian}) + bg = BipartiteGraph(S; symmetric_pattern=A isa Union{Symmetric,Hermitian}) color = partial_distance2_coloring(bg, Val(2), algo.order) return color end function ADTypes.row_coloring(A::AbstractMatrix, algo::GreedyColoringAlgorithm) S = convert(SparseMatrixCSC, A) - bg = bipartite_graph(S; symmetric_pattern=A isa Union{Symmetric,Hermitian}) + bg = BipartiteGraph(S; symmetric_pattern=A isa Union{Symmetric,Hermitian}) color = partial_distance2_coloring(bg, Val(1), algo.order) return color end function ADTypes.symmetric_coloring(A::AbstractMatrix, algo::GreedyColoringAlgorithm) S = convert(SparseMatrixCSC, A) - ag = adjacency_graph(S) + ag = AdjacencyGraph(S) color, star_set = star_coloring(ag, algo.order) return color end diff --git a/src/order.jl b/src/order.jl index 34a0c982..0d2afe64 100644 --- a/src/order.jl +++ b/src/order.jl @@ -21,7 +21,7 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices using their index in th """ struct NaturalOrder <: AbstractOrder end -function vertices(g::Graph, ::NaturalOrder) +function vertices(g::AdjacencyGraph, ::NaturalOrder) return vertices(g) end @@ -40,7 +40,7 @@ end RandomOrder() = RandomOrder(default_rng()) -function vertices(g::Graph, order::RandomOrder) +function vertices(g::AdjacencyGraph, order::RandomOrder) return randperm(order.rng, nb_vertices(g)) end @@ -55,7 +55,7 @@ Instance of [`AbstractOrder`](@ref) which sorts vertices using their degree in t """ struct LargestFirst <: AbstractOrder end -function vertices(g::Graph, ::LargestFirst) +function vertices(g::AdjacencyGraph, ::LargestFirst) criterion(v) = degree(g, v) return sort(vertices(g); by=criterion, rev=true) end diff --git a/test/allocations.jl b/test/allocations.jl index 439b98b8..36e67959 100644 --- a/test/allocations.jl +++ b/test/allocations.jl @@ -10,7 +10,7 @@ rng = StableRNG(63) function test_noallocs_distance2_coloring(n) bench = @be (; - bg=bipartite_graph(sprand(rng, n, n, 5 / n)), + bg=BipartiteGraph(sprand(rng, n, n, 5 / n)), color=Vector{Int}(undef, n), forbidden_colors=Vector{Int}(undef, n), ) partial_distance2_coloring!(_.color, _.forbidden_colors, _.bg, Val(1), 1:n) evals = 1 diff --git a/test/graph.jl b/test/graph.jl index 7ef4fb03..31d56f03 100644 --- a/test/graph.jl +++ b/test/graph.jl @@ -1,9 +1,9 @@ using LinearAlgebra using SparseArrays using SparseMatrixColorings: - Graph, - adjacency_graph, - bipartite_graph, + SparsityPatternCSC, + AdjacencyGraph, + BipartiteGraph, degree, degree_dist2, nb_vertices, @@ -11,54 +11,20 @@ using SparseMatrixColorings: neighbors using Test -## Standard graph +## SparsityPatternCSC -@testset "Graph" begin - g = Graph{true}(sparse([ - 1 0 1 1 - 1 1 0 0 - 0 0 0 1 - ])) - gᵀ = transpose(g) - - @test nb_vertices(g) == 4 - @test nb_edges(g) == 6 - @test nnz(g) == 6 - @test neighbors(g, 1) == [1, 2] - @test neighbors(g, 2) == [2] - @test neighbors(g, 3) == [1] - @test neighbors(g, 4) == [1, 3] - @test degree(g, 1) == 2 - @test degree(g, 2) == 1 - @test degree(g, 3) == 1 - @test degree(g, 4) == 2 - - @test nb_vertices(gᵀ) == 3 - @test nb_edges(gᵀ) == 6 - @test nnz(gᵀ) == 6 - @test neighbors(gᵀ, 1) == [1, 3, 4] - @test neighbors(gᵀ, 2) == [1, 2] - @test neighbors(gᵀ, 3) == [4] - @test degree(gᵀ, 1) == 3 - @test degree(gᵀ, 2) == 2 - @test degree(gᵀ, 3) == 1 - - g = Graph{false}(sparse([ - 1 0 1 - 1 1 0 - 0 0 0 - ])) - - @test nb_vertices(g) == 3 - @test nb_edges(g) == 2 - @test nnz(g) == 4 - @test collect(neighbors(g, 1)) == [2] - @test collect(neighbors(g, 2)) == Int[] - @test collect(neighbors(g, 3)) == [1] - @test degree(g, 1) == 1 - @test degree(g, 2) == 0 - @test degree(g, 3) == 1 -end; +@testset "SparsityPatternCSC" begin + @testset "Transpose" begin + for _ in 1:1000 + A = sprand(rand(100:1000), rand(100:1000), 0.1) + S = SparsityPatternCSC(A) + Sᵀ = transpose(S) + Sᵀ_true = SparsityPatternCSC(sparse(transpose(A))) + @test Sᵀ.colptr == Sᵀ_true.colptr + @test Sᵀ.rowval == Sᵀ_true.rowval + end + end +end ## Bipartite graph (fig 3.1 of "What color is your Jacobian?") @@ -70,8 +36,8 @@ end; 0 0 0 1 1 1 1 0 ]) - bg = bipartite_graph(A; symmetric_pattern=false) - @test_throws DimensionMismatch bipartite_graph(A; symmetric_pattern=true) + bg = BipartiteGraph(A; symmetric_pattern=false) + @test_throws DimensionMismatch BipartiteGraph(A; symmetric_pattern=true) @test nb_vertices(bg, Val(1)) == 4 @test nb_vertices(bg, Val(2)) == 8 # neighbors of rows @@ -103,7 +69,7 @@ end; 1 0 1 0 1 1 0 1 ]) - bg = bipartite_graph(A; symmetric_pattern=true) + bg = BipartiteGraph(A; symmetric_pattern=true) @test nb_vertices(bg, Val(1)) == 4 @test nb_vertices(bg, Val(2)) == 4 # neighbors of rows and columns @@ -124,7 +90,7 @@ end; ]) B = transpose(A) * A - g = adjacency_graph(B - Diagonal(B)) + g = AdjacencyGraph(B - Diagonal(B)) @test nb_vertices(g) == 8 @test collect(neighbors(g, 1)) == [6, 7, 8] @test collect(neighbors(g, 2)) == [5, 7, 8] @@ -135,14 +101,3 @@ end; @test collect(neighbors(g, 7)) == [1, 2, 4, 5, 6, 8] @test collect(neighbors(g, 8)) == [1, 2, 3, 5, 6, 7] end - -@testset "Transpose" begin - for _ in 1:1000 - A = sprand(rand(100:1000), rand(100:1000), 0.1) - g = Graph{true}(A) - gᵀ = transpose(g) - gᵀ_true = Graph{true}(sparse(transpose(A))) - @test gᵀ.colptr == gᵀ_true.colptr - @test gᵀ.rowval == gᵀ_true.rowval - end -end diff --git a/test/order.jl b/test/order.jl index 1fdad8d7..ba819e97 100644 --- a/test/order.jl +++ b/test/order.jl @@ -1,9 +1,8 @@ using SparseArrays using SparseMatrixColorings: BipartiteGraph, - Graph, - adjacency_graph, - bipartite_graph, + AdjacencyGraph, + BipartiteGraph, LargestFirst, NaturalOrder, RandomOrder, @@ -16,31 +15,31 @@ rng = StableRNG(63) @testset "NaturalOrder" begin A = sprand(rng, Bool, 5, 5, 0.5) - ag = adjacency_graph(A) + ag = AdjacencyGraph(A) @test vertices(ag, NaturalOrder()) == 1:5 A = sprand(rng, Bool, 5, 4, 0.5) - bg = bipartite_graph(A) + bg = BipartiteGraph(A) @test vertices(bg, Val(1), NaturalOrder()) == 1:5 A = sprand(rng, Bool, 5, 4, 0.5) - bg = bipartite_graph(A) + bg = BipartiteGraph(A) @test vertices(bg, Val(2), NaturalOrder()) == 1:4 end; @testset "RandomOrder" begin A = sprand(rng, Bool, 5, 5, 0.5) - ag = adjacency_graph(A) + ag = AdjacencyGraph(A) @test sort(vertices(ag, RandomOrder(rng))) == 1:5 @test sort(vertices(ag, RandomOrder())) == 1:5 A = sprand(rng, Bool, 5, 4, 0.5) - bg = bipartite_graph(A) + bg = BipartiteGraph(A) @test sort(vertices(bg, Val(1), RandomOrder(rng))) == 1:5 @test sort(vertices(bg, Val(1), RandomOrder())) == 1:5 A = sprand(rng, Bool, 5, 4, 0.5) - bg = bipartite_graph(A) + bg = BipartiteGraph(A) @test sort(vertices(bg, Val(2), RandomOrder(rng))) == 1:4 @test sort(vertices(bg, Val(2), RandomOrder())) == 1:4 end; @@ -51,7 +50,7 @@ end; 1 0 0 0 1 0 ]) - ag = adjacency_graph(A) + ag = AdjacencyGraph(A) @test vertices(ag, LargestFirst()) == [2, 1, 3] @@ -62,7 +61,7 @@ end; 0 0 0 0 1 0 1 0 ]) - bg = bipartite_graph(A) + bg = BipartiteGraph(A) for side in (1, 2) true_order = sort( diff --git a/test/suitesparse.jl b/test/suitesparse.jl index 5f090799..253384b2 100644 --- a/test/suitesparse.jl +++ b/test/suitesparse.jl @@ -4,9 +4,8 @@ using LinearAlgebra using MatrixDepot using SparseArrays using SparseMatrixColorings: - Graph, - adjacency_graph, - bipartite_graph, + AdjacencyGraph, + BipartiteGraph, LargestFirst, NaturalOrder, degree, @@ -35,7 +34,7 @@ colpack_table_6_7 = CSV.read( @info "Testing distance-2 coloring for $(row[:name]) against ColPack paper" original_mat = matrixdepot("$(row[:group])/$(row[:name])") mat = dropzeros(original_mat) - bg = bipartite_graph(mat) + bg = BipartiteGraph(mat) @test nb_vertices(bg, Val(1)) == row[:V1] @test nb_vertices(bg, Val(2)) == row[:V2] @test nb_edges(bg) == row[:E] @@ -63,7 +62,7 @@ what_table_31_32 = CSV.read( @info "Testing distance-2 coloring for $(row[:name]) against survey paper" original_mat = matrixdepot("$(row[:group])/$(row[:name])") mat = original_mat # no dropzeros - bg = bipartite_graph(mat) + bg = BipartiteGraph(mat) @test nb_vertices(bg, Val(1)) == row[:m] @test nb_vertices(bg, Val(2)) == row[:n] @test nb_edges(bg) == row[:nnz] @@ -93,10 +92,10 @@ what_table_41_42 = CSV.read( @info "Testing star coloring for $(row[:name]) against survey paper" original_mat = matrixdepot("$(row[:group])/$(row[:name])") mat = dropzeros(sparse(original_mat)) - ag = adjacency_graph(mat) - bg = bipartite_graph(mat) + ag = AdjacencyGraph(mat) + bg = BipartiteGraph(mat) @test nb_vertices(ag) == row[:V] - @test nb_edges(ag) ÷ 2 == row[:E] + @test nb_edges(ag) == row[:E] @test maximum_degree(ag) == row[:Δ] @test minimum_degree(ag) == row[:δ] color_N, _ = star_coloring(ag, NaturalOrder())