diff --git a/.github/workflows/IntegrationTest.yml b/.github/workflows/IntegrationTest.yml index 1801cdb..373926f 100644 --- a/.github/workflows/IntegrationTest.yml +++ b/.github/workflows/IntegrationTest.yml @@ -4,6 +4,8 @@ on: branches: - "main" tags: "*" + paths: + - "Project.toml" pull_request_target: types: - "opened" diff --git a/Project.toml b/Project.toml index 140c7af..4f4bc03 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "DataGraphs" uuid = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" -version = "0.3.17" +version = "0.4.0" authors = ["Matthew Fishman and contributors"] [workspace] @@ -22,6 +22,6 @@ DataGraphsGraphsFlowsExt = "GraphsFlows" Dictionaries = "0.4" Graphs = "1" GraphsFlows = "0.1.1" -NamedGraphs = "0.10" +NamedGraphs = "0.11" SimpleTraits = "0.9" julia = "1.7" diff --git a/docs/Project.toml b/docs/Project.toml index 6dc61c2..23e2179 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -8,7 +8,7 @@ Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" path = ".." [compat] -DataGraphs = "0.3" +DataGraphs = "0.4" Documenter = "1.10" ITensorFormatter = "0.2.27" Literate = "2.20.1" diff --git a/examples/Project.toml b/examples/Project.toml index 44b4e85..74d4a80 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -7,6 +7,6 @@ NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" path = ".." [compat] -DataGraphs = "0.3" +DataGraphs = "0.4" Graphs = "1.12" -NamedGraphs = "0.10" +NamedGraphs = "0.11" diff --git a/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl b/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl index 4b181e8..e5dd703 100644 --- a/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl +++ b/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl @@ -2,7 +2,18 @@ module DataGraphsGraphsFlowsExt using DataGraphs: AbstractDataGraph, underlying_graph using GraphsFlows: GraphsFlows -function GraphsFlows.mincut(graph::AbstractDataGraph, args...; kwargs...) - return GraphsFlows.mincut(underlying_graph(graph), args...; kwargs...) +function GraphsFlows.mincut( + graph::AbstractDataGraph, + source_vertex, + target_vertex; + kwargs... + ) + return GraphsFlows.mincut( + underlying_graph(graph), + source_vertex, + target_vertex; + kwargs... + ) end + end diff --git a/src/abstractdatagraph.jl b/src/abstractdatagraph.jl index 3c63b6e..2fefa68 100644 --- a/src/abstractdatagraph.jl +++ b/src/abstractdatagraph.jl @@ -1,16 +1,14 @@ using Dictionaries: Indices, set!, unset! -using Graphs: Graphs, AbstractEdge, IsDirected, a_star, add_edge!, add_vertex!, edges, ne, - nv, steiner_tree, vertices -using NamedGraphs.GraphsExtensions: GraphsExtensions, add_vertices!, arrange_edge, - incident_edges, is_edge_arranged, similar_graph, vertextype +using Graphs: Graphs, AbstractEdge, IsDirected, a_star, add_edge!, add_vertex!, edges, + indegree, induced_subgraph, ne, nv, outdegree, steiner_tree, vertices +using NamedGraphs.GraphsExtensions: GraphsExtensions, add_edges!, add_vertices!, + arrange_edge, incident_edges, is_edge_arranged, rem_edges, vertextype using NamedGraphs.OrdinalIndexing: OrdinalSuffixedInteger using NamedGraphs.SimilarType: similar_type using NamedGraphs: NamedGraphs, AbstractEdges, AbstractNamedEdge, AbstractNamedGraph, - AbstractVertices, position_graph_type + AbstractVertices, NamedDiGraph, NamedGraph, position_graph_type, similar_graph using SimpleTraits: SimpleTraits, @traitfn, Not -is_underlying_graph(::Type{<:AbstractNamedGraph}) = true - abstract type AbstractDataGraph{V, VD, ED} <: AbstractNamedGraph{V} end vertex_data_type(::Type{<:AbstractGraph}) = Any @@ -77,7 +75,11 @@ function NamedGraphs.position_graph_type(type::Type{<:AbstractDataGraph}) return position_graph_type(underlying_graph_type(type)) end -Base.zero(graph_type::Type{<:AbstractDataGraph}) = similar_graph(graph_type) +function Base.copyto!(dst_graph::AbstractDataGraph, src_graph::AbstractDataGraph) + vertex_data(dst_graph) .= vertex_data(src_graph) + edge_data(dst_graph) .= edge_data(src_graph) + return dst_graph +end # Graphs overloads function Graphs.vertices(graph::AbstractDataGraph) @@ -104,49 +106,100 @@ GraphsExtensions.directed_graph_type(::AbstractDataGraph) = not_implemented() GraphsExtensions.undirected_graph_type(::AbstractDataGraph) = not_implemented() # Thase canot be implemented abstractly. -function GraphsExtensions.convert_vertextype(vertextype::Type, graph::AbstractDataGraph) - return not_implemented() +GraphsExtensions.convert_vertextype(::Type, ::AbstractDataGraph) = not_implemented() + +function Base.:(==)(dg1::AbstractDataGraph, dg2::AbstractDataGraph) + underlying_graph(dg1) == underlying_graph(dg2) || return false + vertex_data(dg1) == vertex_data(dg2) || return false + edge_data(dg1) == edge_data(dg2) || return false + return true +end + +# ============================ `similar_graph` (value domain) ============================ # + +""" + similar_graph(datagraph::AbstractDataGraph, D::Type) + similar_graph(datagraph::AbstractDataGraph, D::Type, vertices) + similar_graph(datagraph::AbstractDataGraph, VD::Type, ED::Type) + similar_graph(datagraph::AbstractDataGraph, VD::Type, ED::Type, vertices) + +Create an uninitialized data graph, similar to the provided `datagraph`, but with vertices +defined by `vertices` and a vertex and edge data type `D`. One may also provide separate +vertex and edge data types `VD` and `ED`. +If vertices are not provided, then the graph is constructed with the same vertices and edges +as the input graph. +""" +function NamedGraphs.similar_graph( + graph::AbstractDataGraph + ) + VD = vertex_data_type(graph) + ED = edge_data_type(graph) + return similar_graph(graph, VD, ED) end -# Fix for ambiguity error with `AbstractGraph` version -function Graphs.degree(graph::AbstractDataGraph, vertex::Integer) - return Graphs.degree(underlying_graph(graph), vertex) +function NamedGraphs.similar_graph( + graph::AbstractDataGraph, + vertices + ) + VD = vertex_data_type(graph) + ED = edge_data_type(graph) + return similar_graph(graph, VD, ED, vertices) end - -# Fix for ambiguity error with `AbstractGraph` version -function Graphs.dijkstra_shortest_paths( - graph::AbstractDataGraph, vertices::Vector{<:Integer} +function NamedGraphs.similar_graph( + graph::AbstractDataGraph, + D::Type ) - return Graphs.dijkstra_shortest_paths(underlying_graph(graph), vertices) + return similar_graph(graph, D, D) end -# Fix for ambiguity error with `AbstractGraph` version -function Graphs.eccentricity(graph::AbstractDataGraph, distmx::AbstractMatrix) - return Graphs.eccentricity(underlying_graph(graph), distmx) +function NamedGraphs.similar_graph( + graph::AbstractDataGraph, + D::Type, + vertices + ) + return similar_graph(graph, D, D, vertices) end -# Fix for ambiguity error with `AbstractGraph` version -function Graphs.indegree(graph::AbstractDataGraph, vertex::Integer) - return indegree(underlying_graph(graph), vertex) -end +function NamedGraphs.similar_graph( + graph::AbstractDataGraph, + VD::Type, + ED::Type + ) + new_graph = similar_graph(graph, VD, ED, vertices(graph)) + add_edges!(new_graph, edges(graph)) -# Fix for ambiguity error with `AbstractGraph` version -function Graphs.outdegree(graph::AbstractDataGraph, vertex::Integer) - return outdegree(underlying_graph(graph), vertex) + return new_graph end -# Fix for ambiguity error with `AbstractGraph` version -function Graphs.a_star( - graph::AbstractDataGraph, source::Integer, destination::Integer, args... +# Base case(s) (overload these if fallback not wanted). +@traitfn function NamedGraphs.similar_graph( + graph::AbstractDataGraph::(!IsDirected), + VD::Type, + ED::Type, + vertices + ) + underlying_graph = similar_graph(NamedGraph, vertices) + + return DataGraph(underlying_graph; vertex_data_type = VD, edge_data_type = ED) +end +@traitfn function NamedGraphs.similar_graph( + graph::AbstractDataGraph::IsDirected, + VD::Type, + ED::Type, + vertices ) - return a_star(underlying_graph(graph), source, destination, args...) + underlying_graph = similar_graph(NamedDiGraph, vertices) + + return DataGraph(underlying_graph; vertex_data_type = VD, edge_data_type = ED) end # Fix for ambiguity error with `AbstractGraph` version -@traitfn function Graphs.steiner_tree( - graph::AbstractDataGraph::(!IsDirected), term_vert::Vector{<:Integer}, args... +function Graphs.eccentricity( + graph::AbstractDataGraph, + vertex::Integer, + distmx::AbstractMatrix{<:Real} = NamedGraphs.weights(graph) ) - return steiner_tree(underlying_graph(graph), term_vert, args...) + return NamedGraphs.namedgraph_eccentricity(graph, vertex, distmx) end @traitfn GraphsExtensions.directed_graph(graph::AbstractDataGraph::IsDirected) = graph @@ -156,8 +209,15 @@ function reverse_data_direction(graph::AbstractDataGraph, edge::AbstractEdge, da return is_edge_arranged(graph, edge) ? data : reverse_data_direction(graph, data) end +# Fallback to constructing a concrete `DataGraph`. @traitfn function GraphsExtensions.directed_graph(graph::AbstractDataGraph::(!IsDirected)) - digraph = directed_graph(typeof(graph))(directed_graph(underlying_graph(graph))) + underlying_digraph = similar_graph(NamedDiGraph, vertices(graph)) # edgeless + + VD = vertex_data_type(graph) + ED = edge_data_type(graph) + + digraph = DataGraph(underlying_digraph; vertex_data_type = VD, edge_data_type = ED) + for v in vertices(graph) # TODO: Only loop over `keys(vertex_data(graph))` if isassigned(graph, v) @@ -178,12 +238,9 @@ end end function GraphsExtensions.rename_vertices(f::Function, graph::AbstractDataGraph) - # Uses the two-argument `similar_graph` method so the new graph has correct vertex type renamed_vertices = map(f, vertices(graph)) - renamed_graph = similar_graph(graph, eltype(renamed_vertices)) - - add_vertices!(renamed_graph, renamed_vertices) + renamed_graph = similar_graph(graph, renamed_vertices) for vertex in vertices(graph) if isassigned(graph, vertex) @@ -203,13 +260,7 @@ function GraphsExtensions.rename_vertices(f::Function, graph::AbstractDataGraph) end function Base.reverse(graph::AbstractDataGraph) - reversed_graph = similar_graph(graph) - for v in vertices(graph) - add_vertex!(reversed_graph, v) - if isassigned(graph, v) - reversed_graph[v] = graph[v] - end - end + reversed_graph = rem_edges(graph, edges(graph)) for e in edges(graph) add_edge!(reversed_graph, reverse(e)) if isassigned(graph, e) @@ -281,24 +332,6 @@ function Graphs.rem_edge!(graph::AbstractDataGraph, edge) return graph end -# Fix ambiguity with: -# Graphs.neighbors(graph::AbstractGraph, v::Integer) -function Graphs.neighbors(graph::AbstractDataGraph, v::Integer) - return Graphs.neighbors(underlying_graph(graph), v) -end - -# Fix ambiguity with: -# Graphs.bfs_tree(graph::AbstractGraph, s::Integer; dir) -function Graphs.bfs_tree(graph::AbstractDataGraph, s::Integer; kwargs...) - return Graphs.bfs_tree(underlying_graph(graph), s; kwargs...) -end - -# Fix ambiguity with: -# Graphs.dfs_tree(graph::AbstractGraph, s::Integer; dir) -function Graphs.dfs_tree(graph::AbstractDataGraph, s::Integer; kwargs...) - return Graphs.dfs_tree(underlying_graph(graph), s; kwargs...) -end - function map_vertex_data(f, graph::AbstractGraph; vertices = nothing) new_graph = copy(graph) vs = isnothing(vertices) ? Graphs.vertices(graph) : vertices @@ -342,13 +375,7 @@ function Base.get(default::Base.Callable, graph::AbstractDataGraph, key) end function NamedGraphs.induced_subgraph_from_vertices(graph::AbstractDataGraph, subvertices) - return induced_subgraph_datagraph(graph, subvertices) -end -function induced_subgraph_datagraph(graph::AbstractDataGraph, subvertices) - underlying_subgraph, vlist = - Graphs.induced_subgraph(underlying_graph(graph), subvertices) - - subgraph = similar_graph(graph, underlying_subgraph) + subgraph, vlist = similar_induced_subgraph(graph, subvertices) for v in vertices(subgraph) if isassigned(graph, v) @@ -360,12 +387,24 @@ function induced_subgraph_datagraph(graph::AbstractDataGraph, subvertices) subgraph[e] = graph[e] end end + + # TODO: It would be nice to have `copyto!(subgraph, graph)` do the above. + + return subgraph, vlist +end + +function similar_induced_subgraph(graph::AbstractDataGraph, subvertices) + underlying_subgraph, vlist = induced_subgraph(underlying_graph(graph), subvertices) + + VD = vertex_data_type(graph) + ED = edge_data_type(graph) + + subgraph = DataGraph(underlying_subgraph; vertex_data_type = VD, edge_data_type = ED) + return subgraph, vlist end -# -# Printing -# +# ======================================= printing ======================================= # function Base.show(io::IO, mime::MIME"text/plain", graph::AbstractDataGraph) println(io, "$(typeof(graph)) with $(nv(graph)) vertices:") diff --git a/src/datagraph.jl b/src/datagraph.jl index cf317f1..4a6b2fd 100644 --- a/src/datagraph.jl +++ b/src/datagraph.jl @@ -1,8 +1,8 @@ using Dictionaries: Dictionary -using Graphs: Graphs, edgetype, has_edge, has_vertex -using NamedGraphs.GraphsExtensions: convert_vertextype, directed_graph, directed_graph_type, - rename_vertices, similar_graph, vertextype -using NamedGraphs: GenericNamedGraph +using Graphs: Graphs, bfs_tree, dfs_tree, edgetype, has_edge, has_vertex +using NamedGraphs.GraphsExtensions: + convert_vertextype, directed_graph, directed_graph_type, rename_vertices, vertextype +using NamedGraphs: GenericNamedGraph, similar_graph # TODO: define VertexDataGraph, a graph with only data on the # vertices, and EdgeDataGraph, a graph with only data on the edges. @@ -53,28 +53,48 @@ edge_data_type(G::Type{<:DataGraph}) = eltype(fieldtype(G, :edge_data)) # Extras -function GraphsExtensions.similar_graph(T::Type{<:DataGraph}) - similar_underlying_graph = similar_graph(underlying_graph_type(T)) - return T(similar_underlying_graph) -end -function GraphsExtensions.similar_graph(dg::DataGraph, underlying_graph::AbstractGraph) - return DataGraph( - underlying_graph; - vertex_data_type = vertex_data_type(dg), - edge_data_type = edge_data_type(dg) +# Overwrite the `AbstractDataGraph` fallback (even though they coincide for `DataGraph`) +function NamedGraphs.similar_graph( + graph::DataGraph, + vertex_data_type::Type, + edge_data_type::Type, + vertices + ) + new_underlying_graph = similar_graph( + underlying_graph(graph), + vertices ) + + return DataGraph(new_underlying_graph; vertex_data_type, edge_data_type) end +function NamedGraphs.similar_graph( + G::Type{<:DataGraph}, + vertices + ) + new_underlying_graph = similar_graph( + underlying_graph_type(G), + vertices + ) + + VD = vertex_data_type(G) + ED = edge_data_type(G) + + V = vertextype(G) + + return DataGraph{V}(new_underlying_graph; vertex_data_type = VD, edge_data_type = ED) +end function Base.copy(graph::DataGraph) # Need to manually copy the keys of Dictionaries, see: # https://github.com/andyferris/Dictionaries.jl/issues/98 return _DataGraph( - copy(underlying_graph(graph)), copy(vertex_data(graph)), copy(edge_data(graph)) + copy(graph.underlying_graph), copy(graph.vertex_data), copy(graph.edge_data) ) end function DataGraph{V}( - underlying_graph::AbstractGraph; vertex_data_type::Type = Any, + underlying_graph::AbstractGraph; + vertex_data_type::Type = Any, edge_data_type::Type = Any ) where {V} converted_underlying_graph = convert_vertextype(V, underlying_graph) @@ -107,12 +127,12 @@ DataGraph{V}(graph::DataGraph{V}) where {V} = copy(graph) function DataGraph{V}(graph::DataGraph) where {V} # TODO: Make sure this properly copies converted_underlying_graph = convert_vertextype(V, underlying_graph(graph)) - converted_vertex_data = Dictionary{V}(vertex_data(graph)) - # This doesn't convert properly. - # converted_edge_data = Dictionary{edgetype(converted_underlying_graph)}(edge_data(graph)) + converted_vertex_data = Dictionary{V}(assigned_vertex_data(graph)) + + old_edge_data = assigned_edge_data(graph) converted_edge_data = Dictionary( - edgetype(converted_underlying_graph).(keys(edge_data(graph))), - values(edge_data(graph)) + edgetype(converted_underlying_graph).(keys(old_edge_data)), + collect(old_edge_data) ) return _DataGraph( converted_underlying_graph, diff --git a/src/dataview.jl b/src/dataview.jl index 158b1c7..8eb055f 100644 --- a/src/dataview.jl +++ b/src/dataview.jl @@ -66,18 +66,17 @@ function Base.isassigned(view::EdgeDataView, key::Pair) return isassigned(view, to_graph_index(view.graph, key)) end +Base.getindex(view::VertexOrEdgeDataView, key) = _getindex(view, key) +# For method ambiguity: Base.getindex(view::VertexOrEdgeDataView{K}, key::K) where {K} = _getindex(view, key) -function Base.getindex(view::VertexOrEdgeDataView, key) - return _getindex(view, to_graph_index(view.graph, key)) -end function _getindex(view::VertexDataView, key) - key in keys(view) || throw(IndexError("VertexDataView does not contain index: $key")) - return get_vertex_data(view.graph, key) + isassigned(view, key) || throw(IndexError("VertexDataView does not contain index $key")) + return getindex(view.graph, key) end function _getindex(view::EdgeDataView, key) - key in keys(view) || throw(IndexError("EdgeDataView does not contain index: $key")) - return get_edge_data(view.graph, key) + isassigned(view, key) || throw(IndexError("EdgeDataView does not contain index $key")) + return getindex(view.graph, key) end # Support indexing with `Indices`. @@ -100,9 +99,17 @@ function Base.setindex!(view::EdgeDataView{<:Any, V}, data::V, key::Pair) where end function Base.copyto!(dest::VertexOrEdgeDataView, bc::Dictionaries.BroadcastedDictionary) + + # Deal with the case where `bc` contains pairs. + graph_keys = map(key -> to_graph_index(dest.graph, key), keys(bc)) + + # Check indices match, but don't care about order. + isempty(setdiff(graph_keys, keys(dest))) || throw(IndexError("Indices do not match")) + for (key, val) in pairs(bc) - dest[to_graph_index(dest.graph, key)] = val + dest[graph_keys[key]] = val end + return dest end @@ -127,7 +134,9 @@ end Base.keys(dvs::SubDataView) = dvs.inds Base.getindex(view::SubDataView, key) = getindex_dataview(view, key) +# For method ambiguity: Base.getindex(view::SubDataView{K}, key::K) where {K} = getindex_dataview(view, key) + function getindex_dataview(dvs::SubDataView, key) isassigned(dvs, key) || throw(IndexError("Dictionary does not contain index: $key")) return dvs.view[key] diff --git a/src/lib/DataGraphsPartitionedGraphsExt/src/DataGraphsPartitionedGraphsExt.jl b/src/lib/DataGraphsPartitionedGraphsExt/src/DataGraphsPartitionedGraphsExt.jl index 3373975..e38a523 100644 --- a/src/lib/DataGraphsPartitionedGraphsExt/src/DataGraphsPartitionedGraphsExt.jl +++ b/src/lib/DataGraphsPartitionedGraphsExt/src/DataGraphsPartitionedGraphsExt.jl @@ -1,23 +1,23 @@ module DataGraphsPartitionedGraphsExt -using ..DataGraphs: AbstractDataGraph, DataGraph, DataGraphs, _DataGraph, _getindex, - edge_data, edgetype, get_edge_data, get_edges_data, get_index_data, get_vertex_data, - get_vertices_data, is_edge_assigned, is_graph_index_assigned, is_vertex_assigned, - set_edge_data!, set_edges_data!, set_index_data!, set_vertex_data!, set_vertices_data!, - underlying_graph, vertex_data +using ..DataGraphs: AbstractDataGraph, DataGraph, DataGraphs, IsUnderlyingGraph, _DataGraph, + _getindex, edge_data, edgetype, get_edge_data, get_edges_data, get_index_data, + get_vertex_data, get_vertices_data, is_edge_assigned, is_graph_index_assigned, + is_underlying_graph, is_vertex_assigned, set_edge_data!, set_edges_data!, + set_index_data!, set_vertex_data!, set_vertices_data!, underlying_graph, vertex_data using Dictionaries: Dictionary, IndexError, Indices using Graphs: Graphs, AbstractEdge, AbstractGraph, edges, vertices -using NamedGraphs.GraphsExtensions: - add_vertices!, edge_subgraph, similar_graph, subgraph, vertextype +using NamedGraphs.GraphsExtensions: add_vertices!, edge_subgraph, subgraph, vertextype using NamedGraphs.PartitionedGraphs: AbstractPartitionedGraph, PartitionedGraph, PartitionedGraphs, PartitionedView, QuotientEdge, QuotientEdgeEdge, QuotientEdgeEdges, QuotientEdgeSlice, QuotientEdges, QuotientVertex, QuotientVertexOrEdge, QuotientVertexSlice, QuotientVertexVertex, QuotientVertexVertices, QuotientVertices, QuotientVerticesVertices, QuotientView, departition, has_quotientedge, has_quotientvertex, parent_graph_type, partitioned_vertices, partitionedgraph, - quotient_graph, quotient_graph_vertextype, quotientedges, quotientvertex, - quotientvertices, unpartitioned_graph -using NamedGraphs: - NamedGraphs, Edges, Vertices, get_graph_index, to_edges, to_graph_index, to_vertices + quotient_graph, quotient_graph_type, quotientedges, quotientvertex, quotientvertices, + unpartitioned_graph +using NamedGraphs: NamedGraphs, Edges, Vertices, get_graph_index, similar_graph, to_edges, + to_graph_index, to_vertices +using SimpleTraits: SimpleTraits, @traitfn, Not # ======================== DataGraphs interface for QuotientView ========================= # @@ -50,7 +50,14 @@ function DataGraphs.set_edge_data!(qv::QuotientView, val, e) return qv end -DataGraphs.underlying_graph(qv::QuotientView) = underlying_graph(copy(qv)) +function DataGraphs.is_underlying_graph(qv::Type{<:QuotientView}) + return is_underlying_graph(quotient_graph_type(qv)) +end + +@traitfn DataGraphs.underlying_graph(qv::QuotientView::IsUnderlyingGraph) = copy(qv) +@traitfn function DataGraphs.underlying_graph(qv::QuotientView::(!IsUnderlyingGraph)) + return underlying_graph(copy(qv)) +end function Base.isassigned(qv::QuotientView, ind) return DataGraphs.isassigned_datagraph(qv, to_graph_index(qv, ind)) @@ -158,13 +165,13 @@ function DataGraphs.edge_data_type(T::Type{<:QuotientView}) return Base.promote_op(getindex, PGT, QuotientEdge{vertextype(T), edgetype(T)}) end +# ================================== DataGraph specific ================================== # + # PartitionedGraphs interface -function PartitionedGraphs.partitioned_vertices(dg::AbstractDataGraph) +function PartitionedGraphs.partitioned_vertices(dg::DataGraph) return partitioned_vertices(underlying_graph(dg)) end -# ================================== DataGraph specific ================================== # - function PartitionedGraphs.partitionedgraph(dg::DataGraph, parts) pg = partitionedgraph(underlying_graph(dg), parts) vd = copy(vertex_data(dg)) @@ -188,13 +195,13 @@ function PartitionedGraphs.departition(dg::DataGraph) end end -function quotient_graph_vertex_data(dg) +function quotient_graph_vertex_data(dg::DataGraph) ug = underlying_graph(dg) qvs = QuotientVertexSlice(QuotientVertices(ug)) return map(v -> dg[QuotientVertex(v)], Indices(qvs)) end -function quotient_graph_edge_data(dg) +function quotient_graph_edge_data(dg::DataGraph) ug = underlying_graph(dg) qes = QuotientEdgeSlice(QuotientEdges(ug)) return map(e -> dg[QuotientEdge(e)], Indices(qes)) diff --git a/src/traits/isunderlyinggraph.jl b/src/traits/isunderlyinggraph.jl index 428925f..16d1e20 100644 --- a/src/traits/isunderlyinggraph.jl +++ b/src/traits/isunderlyinggraph.jl @@ -10,3 +10,6 @@ is_underlying_graph(::Type{<:AbstractGraph}) = false using Graphs.SimpleGraphs: AbstractSimpleGraph is_underlying_graph(::Type{<:AbstractSimpleGraph}) = true + +using NamedGraphs: GenericNamedGraph +is_underlying_graph(::Type{<:GenericNamedGraph}) = true diff --git a/test/Project.toml b/test/Project.toml index c3279fc..5ebc3e8 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -15,12 +15,12 @@ path = ".." [compat] Aqua = "0.8.11" -DataGraphs = "0.3" +DataGraphs = "0.4" Dictionaries = "0.4.4" Graphs = "1.12" GraphsFlows = "0.1.1" ITensorPkgSkeleton = "0.3.42" -NamedGraphs = "0.10" +NamedGraphs = "0.11" SafeTestsets = "0.1" Suppressor = "0.2.8" Test = "1.10" diff --git a/test/test_basics.jl b/test/test_basics.jl index 99c4716..727da8d 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -2,14 +2,14 @@ using DataGraphs: DataGraphs, DataGraph, EdgeDataView, VertexDataView, edge_data edge_data_type, underlying_graph, vertex_data, vertex_data_type using Dictionaries: Dictionaries, AbstractDictionary, AbstractIndices, Dictionary, IndexError, Indices, dictionary, unset! -using Graphs: a_star, add_edge!, bfs_tree, connected_components, degree, dfs_tree, - dijkstra_shortest_paths, dst, edges, edgetype, grid, has_edge, has_vertex, indegree, ne, - nv, outdegree, path_graph, src, steiner_tree, vertices +using Graphs: SimpleDiGraph, a_star, add_edge!, bfs_tree, connected_components, degree, + dfs_tree, dijkstra_shortest_paths, dst, edges, edgetype, grid, has_edge, has_vertex, + indegree, is_directed, ne, nv, outdegree, path_graph, src, steiner_tree, vertices using GraphsFlows: GraphsFlows -using NamedGraphs.GraphsExtensions: rename_vertices, subgraph, vertextype, ⊔ +using NamedGraphs.GraphsExtensions: directed_graph, rename_vertices, subgraph, vertextype, ⊔ using NamedGraphs.NamedGraphGenerators: named_grid, named_path_graph using NamedGraphs.OrdinalIndexing: nd, rd, st, th -using NamedGraphs: NamedDiGraph, NamedEdge, NamedGraph +using NamedGraphs: NamedDiGraph, NamedEdge, NamedGraph, empty_graph, similar_graph using Test: @test, @test_broken, @testset @testset "DataGraphs.jl" begin @@ -153,6 +153,32 @@ using Test: @test, @test_broken, @testset @test dg[2 => "Y"] == "edge_Y2" @test dg["Y" => 2] == "edge_Y2" end + @testset "(un)directed graph" begin + dg = DataGraph(named_path_graph(3)) + dg[1 => 2] = "edge_12" + @test dg[1 => 2] == "edge_12" + @test dg[2 => 1] == "edge_12" + dg[2 => 1] = "edge_21" + @test dg[1 => 2] == "edge_21" + @test dg[2 => 1] == "edge_21" + + dg = DataGraph(named_path_graph(3)) + + dg[1 => 2] = "edge_12" + + ddg = directed_graph(dg) + @test !is_directed(dg) + @test is_directed(ddg) + @test isassigned(ddg, 1 => 2) + @test isassigned(ddg, 2 => 1) + @test ddg[1 => 2] == ddg[2 => 1] + + ddg[1 => 2] = "edge_12" + ddg[2 => 1] = "edge_21" + + @test ddg[1 => 2] == "edge_12" + @test ddg[2 => 1] == "edge_21" + end @testset "get and get! functions" begin g = named_grid(4) @@ -355,13 +381,13 @@ using Test: @test, @test_broken, @testset t = bfs_tree(g, 2) es = [2 => 1, 2 => 3, 3 => 4] - @test t isa NamedDiGraph{Int} + @test underlying_graph(t) isa NamedDiGraph{Int} @test nv(t) == nv(g) @test ne(t) == nv(g) - 1 @test all(e -> has_edge(t, e), es) t = dfs_tree(g, 2) - @test t isa NamedDiGraph{Int} + @test underlying_graph(t) isa NamedDiGraph{Int} @test nv(t) == nv(g) @test ne(t) == nv(g) - 1 @test all(e -> has_edge(t, e), es) @@ -550,4 +576,69 @@ using Test: @test, @test_broken, @testset edv["a" => "b"] = 5.0 @test g["a" => "b"] == 5.0 end + + @testset "`similar_graph`" begin + g = DataGraph( + NamedGraph(path_graph(3), ["a", "b", "c"]); + vertex_data_type = Int, + edge_data_type = Float64 + ) + + g["a"] = 1 + g["b"] = 2 + g["c"] = 3 + g["a" => "b"] = -1.0 + g["b" => "c"] = -2.0 + + g2 = similar_graph(g) + + # Test that graph has no data. + @test !isassigned(g2, "a") + @test !isassigned(g2, "b") + @test !isassigned(g2, "c") + @test !isassigned(g2, "a" => "b") + @test !isassigned(g2, "b" => "c") + + @test underlying_graph(g2) == underlying_graph(g) + @test !(underlying_graph(g2) === underlying_graph(g)) + + g2 = similar_graph(g, ["x", "y", "z", "w"]) + + @test has_vertex(g2, "x") + @test has_vertex(g2, "y") + @test has_vertex(g2, "z") + @test has_vertex(g2, "w") + + g_copy = copy(g) + @test g_copy == g + @test !(g_copy === g) + + g_copy = copyto!(similar_graph(g_copy), g) + @test g_copy["a"] == 1 + @test g_copy["b"] == 2 + @test g_copy["c"] == 3 + @test g_copy["a" => "b"] == -1.0 + @test g_copy["b" => "c"] == -2.0 + + @test_throws IndexError copyto!(empty_graph(g_copy), g_copy) + + g2 = similar_graph(g, ["u", "v"]) + @test similar_graph(g2) isa typeof(g) + @test has_vertex(g2, "u") + @test has_vertex(g2, "v") + @test ne(g2) == 0 + + g2 = similar_graph(g, Float64, Int) + @test has_vertex(g2, "a") + @test has_edge(g2, "a" => "b") + @test vertex_data_type(g2) === Float64 + @test edge_data_type(g2) === Int + + g2 = similar_graph(g, String, Tuple, [:a, :b]) + @test vertex_data_type(g2) === String + @test edge_data_type(g2) === Tuple + @test has_vertex(g2, :a) + @test has_vertex(g2, :b) + @test ne(g2) == 0 + end end diff --git a/test/test_partitionedgraphs.jl b/test/test_partitionedgraphs.jl index 6f18ee4..2ee519d 100644 --- a/test/test_partitionedgraphs.jl +++ b/test/test_partitionedgraphs.jl @@ -5,14 +5,14 @@ using DataGraphs: DataGraphs, AbstractDataGraph, DataGraph, EdgeDataView, Vertex vertex_data, vertex_data_type using Dictionaries: Dictionary, IndexError, Indices using Graphs: AbstractGraph, dst, edges, edgetype, has_edge, has_vertex, src, vertices -using NamedGraphs.GraphsExtensions: GraphsExtensions, similar_graph, subgraph, vertextype +using NamedGraphs.GraphsExtensions: GraphsExtensions, subgraph, vertextype using NamedGraphs.NamedGraphGenerators: named_path_graph using NamedGraphs.PartitionedGraphs: PartitionedGraph, PartitionedGraphs, QuotientEdge, QuotientEdges, QuotientVertex, QuotientVertexOrEdge, QuotientVertexVertex, QuotientVertexVertices, QuotientVertices, QuotientVerticesVertices, QuotientView, - departition, partitionedgraph, quotient_graph, quotientedges, quotientvertices, - unpartition -using NamedGraphs: NamedGraphs, Edges, NamedGraph, Vertices + departition, partitioned_vertices, partitionedgraph, quotient_graph, quotientedges, + quotientvertices, unpartition +using NamedGraphs: NamedGraphs, Edges, NamedGraph, Vertices, similar_graph using Test: @test, @test_throws, @testset struct TestDataGraph{V, VD, ED, DG <: DataGraph{V, VD, ED}, QDG} <: @@ -43,11 +43,20 @@ end DataGraphs.underlying_graph(graph::TestDataGraph) = underlying_graph(graph.graph) PartitionedGraphs.quotient_graph(graph::TestDataGraph) = graph.quotientgraph -function GraphsExtensions.similar_graph(dg::TestDataGraph, graph::AbstractGraph) +function PartitionedGraphs.partitioned_vertices(graph::TestDataGraph) + return partitioned_vertices(graph.graph) +end + +function NamedGraphs.similar_graph(dg::TestDataGraph, graph::AbstractGraph) dg = similar_graph(dg.graph, graph) return TestDataGraph(dg) end +function DataGraphs.similar_induced_subgraph(dg::TestDataGraph, subvertices) + dg, vlist = NamedGraphs.induced_subgraph(dg.graph, subvertices) + return TestDataGraph(dg), vlist +end + for f in [ :(DataGraphs.is_vertex_assigned), :(DataGraphs.is_edge_assigned),