diff --git a/Project.toml b/Project.toml index 19af653..09c15cf 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "NamedGraphs" uuid = "678767b0-92e7-4007-89e4-4527a8725b19" authors = ["Matthew Fishman and contributors"] -version = "0.1.0" +version = "0.1.1" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" diff --git a/src/Dictionaries/dictionary.jl b/src/Dictionaries/dictionary.jl new file mode 100644 index 0000000..f2c5a7d --- /dev/null +++ b/src/Dictionaries/dictionary.jl @@ -0,0 +1,8 @@ +# Workaround for: https://github.com/andyferris/Dictionaries.jl/issues/98 +# TODO: Move to Dictionaries.jl file in NamedGraphs.jl +copy_keys_values(d::Dictionary) = Dictionary(copy(d.indices), copy(d.values)) + +# Dictionaries.jl patch +# TODO: delete once fixed in Dictionaries.jl +# TODO: Move to Dictionaries.jl file in NamedGraphs.jl +convert(::Type{Dictionary{I,T}}, dict::Dictionary{I,T}) where {I,T} = dict diff --git a/src/Graphs/abstractgraph.jl b/src/Graphs/abstractgraph.jl index 885b134..3c50f00 100644 --- a/src/Graphs/abstractgraph.jl +++ b/src/Graphs/abstractgraph.jl @@ -5,6 +5,11 @@ undirected_graph(::Type{<:AbstractGraph}) = error("Not implemented") @traitfn directed_graph(graph::::IsDirected) = graph +convert_vertextype(::Type{V}, graph::AbstractGraph{V}) where {V} = graph +function convert_vertextype(V::Type, graph::AbstractGraph) + return not_implemented() +end + # TODO: Handle metadata in a generic way @traitfn function directed_graph(graph::::(!IsDirected)) digraph = directed_graph(typeof(graph))() @@ -48,6 +53,18 @@ function rename_vertices(g::AbstractGraph, name_map) return rename_vertices(v -> name_map[v], g) end +# Returns just the edges of a directed graph, +# but both edge directions of an undirected graph. +# TODO: Move to NamedGraphs.jl +@traitfn function all_edges(g::::IsDirected) + return edges(g) +end + +@traitfn function all_edges(g::::(!IsDirected)) + e = edges(g) + return Iterators.flatten(zip(e, reverse.(e))) +end + # Alternative syntax to `getindex` for getting a subgraph function subgraph(graph::AbstractGraph, subvertices::Vector) return induced_subgraph(graph, subvertices)[1] @@ -250,17 +267,3 @@ end pop!(vertices) return [edgetype(graph)(vertex, parent_vertex(graph, vertex)) for vertex in vertices] end - -######################################################################## -# Graphs.SimpleGraphs extensions - -# TODO: Move to `SimpleGraph` file -# TODO: Use trait dispatch to do no-ops when appropriate -directed_graph(G::Type{<:SimpleGraph}) = SimpleDiGraph{vertextype(G)} -undirected_graph(G::Type{<:SimpleGraph}) = G -directed_graph(G::Type{<:SimpleDiGraph}) = G -undirected_graph(G::Type{<:SimpleDiGraph}) = SimpleGraph{vertextype(G)} - -function set_vertices(graph::AbstractSimpleGraph, vertices::Vector) - return GenericNamedGraph(graph, vertices) -end diff --git a/src/Graphs/simplegraph.jl b/src/Graphs/simplegraph.jl new file mode 100644 index 0000000..b1b0b78 --- /dev/null +++ b/src/Graphs/simplegraph.jl @@ -0,0 +1,13 @@ +######################################################################## +# Graphs.SimpleGraphs extensions + +# TODO: Move to `SimpleGraph` file +# TODO: Use trait dispatch to do no-ops when appropriate +directed_graph(G::Type{<:SimpleGraph}) = SimpleDiGraph{vertextype(G)} +undirected_graph(G::Type{<:SimpleGraph}) = G +directed_graph(G::Type{<:SimpleDiGraph}) = G +undirected_graph(G::Type{<:SimpleDiGraph}) = SimpleGraph{vertextype(G)} + +function set_vertices(graph::AbstractSimpleGraph, vertices::Vector) + return GenericNamedGraph(graph, vertices) +end diff --git a/src/NamedGraphs.jl b/src/NamedGraphs.jl index 481d364..09aef8f 100644 --- a/src/NamedGraphs.jl +++ b/src/NamedGraphs.jl @@ -46,10 +46,12 @@ import Graphs: import Base: show, eltype, copy, getindex, convert, hcat, vcat, hvncat, union # abstractnamededge.jl -import Base: Pair, Tuple, show, ==, hash, eltype +import Base: Pair, Tuple, show, ==, hash, eltype, convert import Graphs: AbstractEdge, src, dst, reverse +include(joinpath("Dictionaries", "dictionary.jl")) include(joinpath("Graphs", "abstractgraph.jl")) +include(joinpath("Graphs", "simplegraph.jl")) include(joinpath("Graphs", "generators", "staticgraphs.jl")) include("abstractnamededge.jl") include("namededge.jl") diff --git a/src/abstractnamededge.jl b/src/abstractnamededge.jl index 179e5b6..70fe72e 100644 --- a/src/abstractnamededge.jl +++ b/src/abstractnamededge.jl @@ -1,10 +1,13 @@ abstract type AbstractNamedEdge{V} <: AbstractEdge{V} end -eltype(::Type{<:ET}) where {ET<:AbstractNamedEdge{T}} where {T} = T +eltype(::Type{<:AbstractNamedEdge{V}}) where {V} = V src(e::AbstractNamedEdge) = not_implemented() dst(e::AbstractNamedEdge) = not_implemented() +convert_vertextype(::Type{V}, E::Type{<:AbstractNamedEdge{V}}) where {V} = E +convert_vertextype(::Type, E::Type{<:AbstractNamedEdge}) = not_implemented() + function show(io::IO, mime::MIME"text/plain", e::AbstractNamedEdge) show(io, src(e)) print(io, " => ") @@ -19,7 +22,7 @@ Pair(e::AbstractNamedEdge) = Pair(src(e), dst(e)) Tuple(e::AbstractNamedEdge) = (src(e), dst(e)) # Convenience functions -reverse(e::T) where {T<:AbstractNamedEdge} = T(dst(e), src(e)) +reverse(e::AbstractNamedEdge) = typeof(e)(dst(e), src(e)) function ==(e1::AbstractNamedEdge, e2::AbstractNamedEdge) return (src(e1) == src(e2) && dst(e1) == dst(e2)) end diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index 3357b0f..a268856 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -21,6 +21,8 @@ undirected_graph(G::Type{<:AbstractNamedGraph}) = not_implemented() # In terms of `parent_graph_type` # is_directed(::Type{<:AbstractNamedGraph}) = not_implemented() +convert_vertextype(::Type, ::AbstractNamedGraph) = not_implemented() + # TODO: implement as: # # graph = set_parent_graph(graph, copy(parent_graph(graph))) @@ -292,7 +294,7 @@ show(io::IO, graph::AbstractNamedGraph) = show(io, MIME"text/plain"(), graph) # Convenience functions # -function Base.:(==)(g1::AbstractNamedGraph, g2::AbstractNamedGraph) +function (g1::AbstractNamedGraph == g2::AbstractNamedGraph) issetequal(vertices(g1), vertices(g2)) || return false for v in vertices(g1) issetequal(inneighbors(g1, v), inneighbors(g2, v)) || return false diff --git a/src/namededge.jl b/src/namededge.jl index dea6a34..99a859c 100644 --- a/src/namededge.jl +++ b/src/namededge.jl @@ -6,6 +6,8 @@ end NamedEdge(src::V, dst::V) where {V} = NamedEdge{V}(src, dst) NamedEdge(src::S, dst::D) where {S,D} = NamedEdge{promote_type(S, D)}(src, dst) +convert_vertextype(V::Type, ::Type{<:NamedEdge}) = NamedEdge{V} + src(e::NamedEdge) = e.src dst(e::NamedEdge) = e.dst diff --git a/src/namedgraph.jl b/src/namedgraph.jl index 742f497..ed0c359 100644 --- a/src/namedgraph.jl +++ b/src/namedgraph.jl @@ -4,6 +4,27 @@ struct GenericNamedGraph{V,G<:AbstractSimpleGraph{Int}} <: AbstractNamedGraph{V} vertex_to_parent_vertex::Dictionary{V,Int} end +function convert_vertextype(V::Type, graph::GenericNamedGraph) + return GenericNamedGraph(parent_graph(graph), convert(Vector{V}, vertices(graph))) +end + +# +# Convert inputs to vertex list +# + +function to_vertices(vertices) + return Vector(vertices) +end +to_vertices(vertices::Vector) = vertices +to_vertices(vertices::Array) = vec(vertices) +# Treat tuple inputs as cartesian grid sizes +function to_vertices(vertices::Tuple{Vararg{Integer}}) + return vec(Tuple.(CartesianIndices(vertices))) +end +function to_vertices(V::Type, vertices) + return convert(Vector{V}, to_vertices(vertices)) +end + # # Constructors from `AbstractSimpleGraph` # @@ -12,13 +33,20 @@ end function GenericNamedGraph{V,G}( parent_graph::AbstractSimpleGraph, vertices::Vector ) where {V,G} + @assert length(vertices) == nv(parent_graph) # Need to copy the vertices here, otherwise the Dictionary uses a view of the vertices return GenericNamedGraph{V,G}( parent_graph, vertices, Dictionary(copy(vertices), eachindex(vertices)) ) end -function GenericNamedGraph{V}(parent_graph::AbstractSimpleGraph, vertices::Vector) where {V} +function GenericNamedGraph{V,G}( + parent_graph::AbstractSimpleGraph, vertices +) where {V,G} + return GenericNamedGraph{V,G}(parent_graph, to_vertices(V, vertices)) +end + +function GenericNamedGraph{V}(parent_graph::AbstractSimpleGraph, vertices) where {V} return GenericNamedGraph{V,typeof(parent_graph)}(parent_graph, vertices) end @@ -28,28 +56,37 @@ function GenericNamedGraph{<:Any,G}( return GenericNamedGraph{eltype(vertices),G}(parent_graph, vertices) end +function GenericNamedGraph{<:Any,G}( + parent_graph::AbstractSimpleGraph, vertices +) where {G} + return GenericNamedGraph{<:Any,G}(parent_graph, to_vertices(vertices)) +end + function GenericNamedGraph(parent_graph::AbstractSimpleGraph, vertices::Vector) - # Need to copy the vertices here, otherwise the Dictionary uses a view of the vertices return GenericNamedGraph{eltype(vertices)}(parent_graph, vertices) end +function GenericNamedGraph(parent_graph::AbstractSimpleGraph, vertices) + return GenericNamedGraph(parent_graph, to_vertices(vertices)) +end + # # Constructors from vertex names # -function GenericNamedGraph{V,G}(vertices::Vector) where {V,G} +function GenericNamedGraph{V,G}(vertices) where {V,G} return GenericNamedGraph(G(length(vertices)), vertices) end -function GenericNamedGraph{V}(vertices::Vector) where {V} +function GenericNamedGraph{V}(vertices) where {V} return GenericNamedGraph{V,SimpleGraph{Int}}(vertices) end -function GenericNamedGraph{<:Any,G}(vertices::Vector) where {G} +function GenericNamedGraph{<:Any,G}(vertices) where {G} return GenericNamedGraph{Any,G}(vertices) end -function GenericNamedGraph(vertices::Vector) +function GenericNamedGraph(vertices) return GenericNamedGraph{eltype(vertices)}(vertices) end @@ -93,34 +130,6 @@ function GenericNamedGraph( return GenericNamedGraph(parent_graph, vertices) end -# -# Convenient cartesian index constructor -# - -function GenericNamedGraph{V,G}( - parent_graph::AbstractSimpleGraph, grid_size::Tuple{Vararg{Int}} -) where {V,G} - vertices = Tuple.(CartesianIndices(grid_size)) - @assert prod(grid_size) == nv(parent_graph) - return GenericNamedGraph{V,G}(parent_graph, vec(vertices)) -end - -function GenericNamedGraph{V}( - parent_graph::AbstractSimpleGraph, grid_size::Tuple{Vararg{Int}} -) where {V} - return GenericNamedGraph{V,typeof(parent_graph)}(parent_graph, grid_size) -end - -function GenericNamedGraph{<:Any,G}( - parent_graph::AbstractSimpleGraph, grid_size::Tuple{Vararg{Int}} -) where {G} - return GenericNamedGraph{typeof(grid_size),G}(parent_graph, grid_size) -end - -function GenericNamedGraph(parent_graph::AbstractSimpleGraph, grid_size::Tuple{Vararg{Int}}) - return GenericNamedGraph{typeof(grid_size),typeof(parent_graph)}(parent_graph, grid_size) -end - # AbstractNamedGraph required interface. # TODO: rename `parent_graph` (type is implied by input) parent_graph_type(::Type{<:GenericNamedGraph{V,G}}) where {V,G} = G