diff --git a/src/SimpleWeightedGraphs.jl b/src/SimpleWeightedGraphs.jl index 9c3842f..4fdb573 100644 --- a/src/SimpleWeightedGraphs.jl +++ b/src/SimpleWeightedGraphs.jl @@ -144,4 +144,12 @@ include("persistence.jl") const WGraph = SimpleWeightedGraph const WDiGraph = SimpleWeightedDiGraph +SimpleWeightedDiGraph(g::SimpleWeightedGraph) = SimpleWeightedDiGraph(g.weights) +SimpleWeightedDiGraph{T,U}(g::SimpleWeightedGraph) where T<:Integer where U<:Real = + SimpleWeightedDiGraph(SparseMatrixCSC{U, T}(g.weights)) + +SimpleWeightedGraph(g::SimpleWeightedDiGraph) = SimpleWeightedGraph(g.weights .+ g.weights') +SimpleWeightedGraph{T,U}(g::SimpleWeightedDiGraph) where T<:Integer where U<:Real = + SimpleWeightedGraph(SparseMatrixCSC{U, T}(g.weights .+ g.weights')) + end # module diff --git a/src/simpleweighteddigraph.jl b/src/simpleweighteddigraph.jl index 8d6cbdd..54064eb 100644 --- a/src/simpleweighteddigraph.jl +++ b/src/simpleweighteddigraph.jl @@ -5,12 +5,34 @@ A type representing a directed graph with weights of type `U`. """ mutable struct SimpleWeightedDiGraph{T<:Integer, U<:Real} <: AbstractSimpleWeightedGraph{T, U} weights::SparseMatrixCSC{U, T} # indexed by [dst, src] + function SimpleWeightedDiGraph{T, U}(adjmx::SparseMatrixCSC{U,T}, permute=true) where T <: Integer where U <: Real + dima,dimb = size(adjmx) + isequal(dima,dimb) || error("Adjacency / distance matrices must be square") + permute ? new{T, U}(permutedims(adjmx)) : new{T, U}(adjmx) + end + + SimpleWeightedDiGraph{T}(adjmx::SparseMatrixCSC{U, T}, permute=true) where T<:Integer where U<:Real = + permute ? new{T, U}(permutedims(adjmx)) : new{T, U}(adjmx) + + SimpleWeightedDiGraph(adjmx::SparseMatrixCSC{U, T}, permute=true) where T<:Integer where U<:Real = + permute ? new{T, U}(permutedims(adjmx)) : new{T, U}(adjmx) end +SimpleWeightedDiGraph(m::AbstractMatrix{U}) where U <: Real = + SimpleWeightedDiGraph{Int, U}(SparseMatrixCSC{U, Int}(m)) +SimpleWeightedDiGraph{T}(m::AbstractMatrix{U}) where T<:Integer where U<:Real = + SimpleWeightedDiGraph{T, U}(SparseMatrixCSC{U, T}(m)) +SimpleWeightedDiGraph{T, U}(m::AbstractMatrix) where T<:Integer where U<:Real = + SimpleWeightedDiGraph{T, U}(SparseMatrixCSC{U, T}(m)) + +SimpleWeightedDiGraph(g::SimpleWeightedDiGraph) = SimpleWeightedDiGraph(g.weights, false) +SimpleWeightedDiGraph{T,U}(g::SimpleWeightedDiGraph) where T<:Integer where U<:Real = + SimpleWeightedDiGraph(SparseMatrixCSC{U, T}(g.weights), false) + + ne(g::SimpleWeightedDiGraph) = nnz(g.weights) -# Graph{UInt8}(6), Graph{Int16}(7), Graph{UInt8}() -function (::Type{SimpleWeightedDiGraph{T, U}})(n::Integer = 0) where T<:Integer where U<:Real +function SimpleWeightedDiGraph{T,U}(n::Integer = 0) where T<:Integer where U<:Real weights = spzeros(U, T, T(n), T(n)) return SimpleWeightedDiGraph{T, U}(weights) end @@ -30,61 +52,27 @@ SimpleWeightedDiGraph(::Type{T}, ::Type{U}) where T<:Integer where U<:Real = Sim # DiGraph(AbstractSimpleGraph) function SimpleWeightedDiGraph(g::LightGraphs.SimpleGraphs.AbstractSimpleGraph, ::Type{U}=Float64) where U <: Real T = eltype(g) - return SimpleWeightedDiGraph{T, U}(adjacency_matrix(g)') + return SimpleWeightedDiGraph{T}(adjacency_matrix(g, U)) end # DiGraph(AbstractSimpleGraph, defaultweight) function SimpleWeightedDiGraph(g::LightGraphs.SimpleGraphs.AbstractSimpleGraph, x::U) where U <: Real T = eltype(g) - return SimpleWeightedDiGraph{T, U}(x.*adjacency_matrix(g, U)') -end - -# SimpleWeightedGraph{T, U}(SimpleGraph) -function (::Type{SimpleWeightedDiGraph{T, U}})(g::LightGraphs.SimpleGraphs.SimpleDiGraph) where T<:Integer where U <: Real - SimpleWeightedDiGraph{T, U}(adjacency_matrix(LightGraphs.SimpleGraphs.SimpleDiGraph{T}(g), U)) + return SimpleWeightedDiGraph{T, U}(x.*adjacency_matrix(g, U)) end # DiGraph(srcs, dsts, weights) function SimpleWeightedDiGraph(i::AbstractVector{T}, j::AbstractVector{T}, v::AbstractVector{U}; combine = +) where T<:Integer where U<:Real m = max(maximum(j), maximum(i)) - SimpleWeightedDiGraph{T, U}(sparse(j, i, v, m, m, combine)) + SimpleWeightedDiGraph{T, U}(sparse(j, i, v, m, m, combine), false) end -# Graph{UInt8}(adjmx) -# function (::Type{SimpleWeightedDiGraph{T, U}})(adjmx::AbstractMatrix) where T<:Integer where U <: Real -# dima,dimb = size(adjmx) -# isequal(dima,dimb) || error("Adjacency / distance matrices must be square") -# issymmetric(adjmx) || error("Adjacency / distance matrices must be symmetric") -# g = SimpleWeightedDiGraph(U.(LinearAlgebra.fillstored!(copy(adjmx), 1))) -# end - -# converts Graph{Int} to Graph{Int32} -# function (::Type{SimpleWeightedDiGraph{T, U}})(g::SimpleWeightedDiGraph) where T<:Integer where U<:Real -# h_fadj = [Vector{T}(x) for x in fadj(g)] -# return SimpleGraph(ne(g), h_fadj) -# end - - -# Graph(adjmx) -SimpleWeightedDiGraph(adjmx::AbstractMatrix) = SimpleWeightedDiGraph{Int, eltype(adjmx)}(adjmx') - -# Graph(digraph). Weights will be added. -# TODO: uncomment this. -SimpleWeightedDiGraph(g::AbstractSimpleWeightedGraph) = SimpleWeightedDiGraph(g.weights) - edgetype(::SimpleWeightedDiGraph{T, U}) where T<:Integer where U<:Real = SimpleWeightedGraphEdge{T,U} edges(g::SimpleWeightedDiGraph) = (SimpleWeightedEdge(x[2], x[1], x[3]) for x in zip(findnz(g.weights)...)) weights(g::SimpleWeightedDiGraph) = g.weights' -function inneighbors(g::SimpleWeightedDiGraph) - mat = SparseMatrixCSC(g.weights') - return [mat.rowval[mat.colptr[i]:mat.colptr[i + 1] - 1] for i in 1:nv(g)] -end -function inneighbors(g::SimpleWeightedDiGraph, v::Integer) - mat = SparseMatrixCSC(g.weights') - return mat.rowval[mat.colptr[v]:mat.colptr[v + 1] - 1] -end +inneighbors(g::SimpleWeightedDiGraph, v::Integer) = g.weights[v,:].nzind # add_edge! will overwrite weights. function add_edge!(g::SimpleWeightedDiGraph, e::SimpleWeightedGraphEdge) @@ -113,7 +101,7 @@ function rem_edge!(g::SimpleWeightedDiGraph, e::SimpleWeightedGraphEdge) end -copy(g::SimpleWeightedDiGraph) = SimpleWeightedDiGraph(copy(g.weights)) +copy(g::SimpleWeightedDiGraph) = SimpleWeightedDiGraph(copy(g.weights')) ==(g::SimpleWeightedDiGraph, h::SimpleWeightedDiGraph) = g.weights == h.weights diff --git a/src/simpleweightededge.jl b/src/simpleweightededge.jl index e34f237..d77bec2 100644 --- a/src/simpleweightededge.jl +++ b/src/simpleweightededge.jl @@ -34,3 +34,5 @@ Tuple(e::AbstractSimpleWeightedEdge) = (src(e), dst(e), weight(e)) # Convenience functions - note that these do not use weight. reverse(e::T) where T<:AbstractSimpleWeightedEdge = T(dst(e), src(e), weight(e)) ==(e1::AbstractSimpleWeightedEdge, e2::AbstractSimpleWeightedEdge) = (src(e1) == src(e2) && dst(e1) == dst(e2)) +==(e1::AbstractSimpleWeightedEdge, e2::AbstractEdge) = (src(e1) == src(e2) && dst(e1) == dst(e2)) +==(e1::AbstractEdge, e2::AbstractSimpleWeightedEdge) = (src(e1) == src(e2) && dst(e1) == dst(e2)) \ No newline at end of file diff --git a/src/simpleweightedgraph.jl b/src/simpleweightedgraph.jl index 6214536..1b7aff1 100644 --- a/src/simpleweightedgraph.jl +++ b/src/simpleweightedgraph.jl @@ -6,13 +6,36 @@ A type representing an undirected graph with weights of type `U`. """ mutable struct SimpleWeightedGraph{T<:Integer, U<:Real} <: AbstractSimpleWeightedGraph{T, U} - weights::SparseMatrixCSC{U, T} # indexed by [dst, src] - SimpleWeightedGraph(a::SparseMatrixCSC{U, T}) where T <: Integer where U <: Real = - new copy(a') + weights::SparseMatrixCSC{U,T} + function SimpleWeightedGraph{T, U}(adjmx::SparseMatrixCSC{U, T}) where T<:Integer where U<:Real + dima,dimb = size(adjmx) + isequal(dima,dimb) || error("Adjacency / distance matrices must be square") + issymmetric(adjmx) || error("Adjacency / distance matrices must be symmetric") + new{T, U}(adjmx) + end + + SimpleWeightedGraph{T}(adjmx::SparseMatrixCSC{U, T}) where T<:Integer where U<:Real = + new{T, U}(adjmx) + + SimpleWeightedGraph(adjmx::SparseMatrixCSC{U, T}) where T<:Integer where U<:Real = + new{T, U}(adjmx) + end ne(g::SimpleWeightedGraph) = nnz(g.weights) รท 2 +SimpleWeightedGraph(m::AbstractMatrix{U}) where U <: Real = + SimpleWeightedGraph{Int, U}(SparseMatrixCSC{U, Int}(m)) +SimpleWeightedGraph{T}(m::AbstractMatrix{U}) where T<:Integer where U<:Real = + SimpleWeightedGraph{T, U}(SparseMatrixCSC{U, T}(m)) +SimpleWeightedGraph{T, U}(m::AbstractMatrix) where T<:Integer where U<:Real = + SimpleWeightedGraph{T, U}(SparseMatrixCSC{U, T}(m)) + + +SimpleWeightedGraph(g::SimpleWeightedGraph) = SimpleWeightedGraph(g.weights) +SimpleWeightedGraph{T,U}(g::SimpleWeightedGraph) where T<:Integer where U<:Real = + SimpleWeightedGraph(SparseMatrixCSC{U, T}(g.weights)) + # Graph{UInt8}(6), Graph{Int16}(7), Graph{UInt8}() function (::Type{SimpleWeightedGraph{T, U}})(n::Integer = 0) where T<:Integer where U<:Real @@ -22,7 +45,7 @@ end # Graph() -SimpleWeightedGraph() = SimpleWeightedGraph{Int, Float64}() +SimpleWeightedGraph() = SimpleWeightedGraph(Matrix{Float64}(undef, 0, 0)) # Graph(6), Graph(0x5) SimpleWeightedGraph(n::T) where T<:Integer = SimpleWeightedGraph{T, Float64}(n) @@ -35,11 +58,11 @@ SimpleWeightedGraph(::Type{T}, ::Type{U}) where T<:Integer where U<:Real = Simpl # Graph(SimpleGraph) SimpleWeightedGraph(g::LightGraphs.SimpleGraphs.SimpleGraph{T}, ::Type{U}=Float64) where T <: Integer where U <: Real = - SimpleWeightedGraph{T, U}(adjacency_matrix(g)) + SimpleWeightedGraph{T, U}(adjacency_matrix(g, U)) # Graph(SimpleDiGraph) SimpleWeightedGraph(g::LightGraphs.SimpleGraphs.SimpleDiGraph{T}, ::Type{U}=Float64) where T <: Integer where U <: Real = - SimpleWeightedGraph{T, U}(adjacency_matrix(LightGraphs.SimpleGraphs.SimpleGraph(g))) + SimpleWeightedGraph{T, U}(adjacency_matrix(LightGraphs.SimpleGraphs.SimpleGraph(g), U)) # Graph(SimpleGraph, defaultweight) SimpleWeightedGraph(g::LightGraphs.SimpleGraphs.SimpleGraph{T}, x::U) where T <: Integer where U <: Real = @@ -54,25 +77,13 @@ function (::Type{SimpleWeightedGraph{T, U}})(g::LightGraphs.SimpleGraphs.SimpleG SimpleWeightedGraph{T, U}(adjacency_matrix(LightGraphs.SimpleGraphs.SimpleGraph{T}(g), U)) end -# DiGraph(srcs, dsts, weights) +# Graph(srcs, dsts, weights) function SimpleWeightedGraph(i::AbstractVector{T}, j::AbstractVector{T}, v::AbstractVector{U}; combine = +) where T<:Integer where U<:Real m = max(maximum(i), maximum(j)) s = sparse(vcat(i,j), vcat(j,i), vcat(v,v), m, m, combine) SimpleWeightedGraph{T, U}(s) end -# Graph(adjmx) -function SimpleWeightedGraph(adjmx::AbstractMatrix) - dima,dimb = size(adjmx) - isequal(dima,dimb) || error("Adjacency / distance matrices must be square") - issymmetric(adjmx) || error("Adjacency / distance matrices must be symmetric") - SimpleWeightedGraph{Int, eltype(adjmx)}(adjmx') -end - -# Graph(digraph). Weights will be added. - -SimpleWeightedGraph(g::SimpleWeightedDiGraph) = SimpleWeightedGraph(g.weights .+ g.weights') - edgetype(::SimpleWeightedGraph{T, U}) where T<:Integer where U<:Real= SimpleWeightedGraphEdge{T,U} edges(g::SimpleWeightedGraph) = (SimpleWeightedEdge(x[1], x[2], x[3]) for x in zip(findnz(triu(g.weights))...)) diff --git a/test/simpleweightedgraph.jl b/test/simpleweightedgraph.jl index 9497c61..f729b0b 100644 --- a/test/simpleweightedgraph.jl +++ b/test/simpleweightedgraph.jl @@ -50,7 +50,6 @@ using SimpleWeightedGraphs @test @inferred(vertices(g)) == 1:4 @test SimpleWeightedEdge(2,3) in edges(g) @test @inferred(nv(g)) == 4 - @test @inferred(outneighbors(g)) == inneighbors(g) @test @inferred(outneighbors(g,2)) == inneighbors(g,2) == neighbors(g,2) @test @inferred(has_edge(g, 2, 3)) @test @inferred(has_edge(g, 3, 2)) @@ -115,8 +114,8 @@ using SimpleWeightedGraphs @test SimpleWeightedEdge(2,3) in edges(g) @test !(SimpleWeightedEdge(3,2) in edges(g)) @test @inferred(nv(g)) == 4 - @test @inferred(outneighbors(g)[2]) == outneighbors(g, 2) == [3] - @test @inferred(inneighbors(g)[2]) == inneighbors(g, 2) == [1] + @test outneighbors(g, 2) == [3] + @test inneighbors(g, 2) == [1] @test @inferred(has_edge(g, 2, 3)) @test @inferred(!has_edge(g, 3, 2))