From c726dcce1a27d09e16f458afd0631d3e52f2254b Mon Sep 17 00:00:00 2001 From: mtfishman <7855256+mtfishman@users.noreply.github.com> Date: Tue, 11 Nov 2025 01:41:02 +0000 Subject: [PATCH] Format .jl files (Runic) --- Project.toml | 2 +- docs/make.jl | 22 +- docs/make_index.jl | 16 +- docs/make_readme.jl | 16 +- examples/README.jl | 2 +- examples/datagraph.jl | 2 +- examples/disjoint_union.jl | 6 +- examples/multidimdatagraph_1d.jl | 2 +- examples/multidimdatagraph_2d.jl | 2 +- examples/slicing.jl | 2 +- .../DataGraphsGraphsFlowsExt.jl | 2 +- .../DataGraphsNamedGraphsExt.jl | 32 +- src/abstractdatagraph.jl | 512 +++++------ src/datagraph.jl | 108 +-- test/runtests.jl | 80 +- test/test_aqua.jl | 2 +- test/test_basics.jl | 834 +++++++++--------- 17 files changed, 822 insertions(+), 820 deletions(-) diff --git a/Project.toml b/Project.toml index c37cad2..d13958a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DataGraphs" uuid = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" +version = "0.2.10" authors = ["Matthew Fishman and contributors"] -version = "0.2.9" [deps] Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" diff --git a/docs/make.jl b/docs/make.jl index a5da3cf..ca11fa4 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,20 +1,20 @@ using DataGraphs: DataGraphs using Documenter: Documenter, DocMeta, deploydocs, makedocs -DocMeta.setdocmeta!(DataGraphs, :DocTestSetup, :(using DataGraphs); recursive=true) +DocMeta.setdocmeta!(DataGraphs, :DocTestSetup, :(using DataGraphs); recursive = true) include("make_index.jl") makedocs(; - modules=[DataGraphs], - authors="ITensor developers and contributors", - sitename="DataGraphs.jl", - format=Documenter.HTML(; - canonical="https://itensor.github.io/DataGraphs.jl", - edit_link="main", - assets=["assets/favicon.ico", "assets/extras.css"], - ), - pages=["Home" => "index.md", "Reference" => "reference.md"], + modules = [DataGraphs], + authors = "ITensor developers and contributors", + sitename = "DataGraphs.jl", + format = Documenter.HTML(; + canonical = "https://itensor.github.io/DataGraphs.jl", + edit_link = "main", + assets = ["assets/favicon.ico", "assets/extras.css"], + ), + pages = ["Home" => "index.md", "Reference" => "reference.md"], ) -deploydocs(; repo="github.com/ITensor/DataGraphs.jl", devbranch="main", push_preview=true) +deploydocs(; repo = "github.com/ITensor/DataGraphs.jl", devbranch = "main", push_preview = true) diff --git a/docs/make_index.jl b/docs/make_index.jl index d48986f..09cc4b0 100644 --- a/docs/make_index.jl +++ b/docs/make_index.jl @@ -2,20 +2,20 @@ using Literate: Literate using DataGraphs: DataGraphs function ccq_logo(content) - include_ccq_logo = """ + include_ccq_logo = """ ```@raw html Flatiron Center for Computational Quantum Physics logo. Flatiron Center for Computational Quantum Physics logo. ``` """ - content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) - return content + content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) + return content end Literate.markdown( - joinpath(pkgdir(DataGraphs), "examples", "README.jl"), - joinpath(pkgdir(DataGraphs), "docs", "src"); - flavor=Literate.DocumenterFlavor(), - name="index", - postprocess=ccq_logo, + joinpath(pkgdir(DataGraphs), "examples", "README.jl"), + joinpath(pkgdir(DataGraphs), "docs", "src"); + flavor = Literate.DocumenterFlavor(), + name = "index", + postprocess = ccq_logo, ) diff --git a/docs/make_readme.jl b/docs/make_readme.jl index 8fcd5b1..e4d6bfb 100644 --- a/docs/make_readme.jl +++ b/docs/make_readme.jl @@ -2,20 +2,20 @@ using Literate: Literate using DataGraphs: DataGraphs function ccq_logo(content) - include_ccq_logo = """ + include_ccq_logo = """ Flatiron Center for Computational Quantum Physics logo. """ - content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) - return content + content = replace(content, "{CCQ_LOGO}" => include_ccq_logo) + return content end Literate.markdown( - joinpath(pkgdir(DataGraphs), "examples", "README.jl"), - joinpath(pkgdir(DataGraphs)); - flavor=Literate.CommonMarkFlavor(), - name="README", - postprocess=ccq_logo, + joinpath(pkgdir(DataGraphs), "examples", "README.jl"), + joinpath(pkgdir(DataGraphs)); + flavor = Literate.CommonMarkFlavor(), + name = "README", + postprocess = ccq_logo, ) diff --git a/examples/README.jl b/examples/README.jl index 5ce4674..ff8937c 100644 --- a/examples/README.jl +++ b/examples/README.jl @@ -1,5 +1,5 @@ # # DataGraphs.jl -# +# # [![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://itensor.github.io/DataGraphs.jl/stable/) # [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://itensor.github.io/DataGraphs.jl/dev/) # [![Build Status](https://github.com/ITensor/DataGraphs.jl/actions/workflows/Tests.yml/badge.svg?branch=main)](https://github.com/ITensor/DataGraphs.jl/actions/workflows/Tests.yml?query=branch%3Amain) diff --git a/examples/datagraph.jl b/examples/datagraph.jl index f46c305..433ba80 100644 --- a/examples/datagraph.jl +++ b/examples/datagraph.jl @@ -2,7 +2,7 @@ using DataGraphs: DataGraph using Graphs: Edge, grid, has_edge, has_vertex g = grid((4,)) -dg = DataGraph(g; vertex_data_eltype=String, edge_data_eltype=Symbol) +dg = DataGraph(g; vertex_data_eltype = String, edge_data_eltype = Symbol) @show !isassigned(dg, Edge(1, 2)) @show !isassigned(dg, 1 => 2) @show !isassigned(dg, Edge(1 => 2)) diff --git a/examples/disjoint_union.jl b/examples/disjoint_union.jl index f06ea4d..0a5dce7 100644 --- a/examples/disjoint_union.jl +++ b/examples/disjoint_union.jl @@ -3,13 +3,13 @@ using NamedGraphs.GraphsExtensions: ⊔ using NamedGraphs.NamedGraphGenerators: named_grid using DataGraphs: DataGraph -g = DataGraph(named_grid((2, 2)); vertex_data_eltype=String, edge_data_eltype=String) +g = DataGraph(named_grid((2, 2)); vertex_data_eltype = String, edge_data_eltype = String) for v in vertices(g) - g[v] = "V$v" + g[v] = "V$v" end for e in edges(g) - g[e] = "E$e" + g[e] = "E$e" end gg = g ⊔ g diff --git a/examples/multidimdatagraph_1d.jl b/examples/multidimdatagraph_1d.jl index 2a06681..91eedd9 100644 --- a/examples/multidimdatagraph_1d.jl +++ b/examples/multidimdatagraph_1d.jl @@ -3,7 +3,7 @@ using Graphs: grid, has_edge, has_vertex using NamedGraphs: NamedGraph, NamedEdge g = NamedGraph(grid((4,)), ["A", "B", "C", "D"]) -dg = DataGraph(g; vertex_data_eltype=String, edge_data_eltype=Symbol) +dg = DataGraph(g; vertex_data_eltype = String, edge_data_eltype = Symbol) @show has_vertex(dg, "A") @show has_vertex(dg, "D") diff --git a/examples/multidimdatagraph_2d.jl b/examples/multidimdatagraph_2d.jl index 92ff83e..6134bbb 100644 --- a/examples/multidimdatagraph_2d.jl +++ b/examples/multidimdatagraph_2d.jl @@ -3,7 +3,7 @@ using NamedGraphs: NamedEdge using NamedGraphs.NamedGraphGenerators: named_grid g = named_grid((2, 2)) -dg = DataGraph(g; vertex_data_eltype=String, edge_data_eltype=String) +dg = DataGraph(g; vertex_data_eltype = String, edge_data_eltype = String) dg[1, 1] = "X11" diff --git a/examples/slicing.jl b/examples/slicing.jl index 85b0644..b4d7cbd 100644 --- a/examples/slicing.jl +++ b/examples/slicing.jl @@ -4,7 +4,7 @@ using NamedGraphs.NamedGraphGenerators: named_grid using Graphs: ne, nv g = named_grid((2, 2)) -dg = DataGraph(g; vertex_data_eltype=String, edge_data_eltype=String) +dg = DataGraph(g; vertex_data_eltype = String, edge_data_eltype = String) dg[1, 1] = "V11" dg[1, 2] = "V12" diff --git a/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl b/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl index e6bf45c..4b181e8 100644 --- a/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl +++ b/ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl @@ -3,6 +3,6 @@ using DataGraphs: AbstractDataGraph, underlying_graph using GraphsFlows: GraphsFlows function GraphsFlows.mincut(graph::AbstractDataGraph, args...; kwargs...) - return GraphsFlows.mincut(underlying_graph(graph), args...; kwargs...) + return GraphsFlows.mincut(underlying_graph(graph), args...; kwargs...) end end diff --git a/ext/DataGraphsNamedGraphsExt/DataGraphsNamedGraphsExt.jl b/ext/DataGraphsNamedGraphsExt/DataGraphsNamedGraphsExt.jl index 6253408..8595bc3 100644 --- a/ext/DataGraphsNamedGraphsExt/DataGraphsNamedGraphsExt.jl +++ b/ext/DataGraphsNamedGraphsExt/DataGraphsNamedGraphsExt.jl @@ -5,11 +5,11 @@ using NamedGraphs: NamedGraphs, AbstractNamedGraph DataGraphs.is_underlying_graph(::Type{<:AbstractNamedGraph}) = true for f in [:(NamedGraphs.position_graph), :(NamedGraphs.vertex_positions)] - @eval begin - function $f(graph::AbstractDataGraph) - return $f(underlying_graph(graph)) + @eval begin + function $f(graph::AbstractDataGraph) + return $f(underlying_graph(graph)) + end end - end end using Graphs: edgetype, vertices @@ -18,23 +18,23 @@ using NamedGraphs.OrdinalIndexing: OrdinalSuffixedInteger # (analagous to Julia's `to_indices`) instead of through # overloading `Base.getindex`. function Base.getindex(graph::AbstractDataGraph, vertex::OrdinalSuffixedInteger) - return graph[vertices(graph)[vertex]] + return graph[vertices(graph)[vertex]] end function Base.getindex( - graph::AbstractDataGraph, edge::Pair{<:OrdinalSuffixedInteger,<:OrdinalSuffixedInteger} -) - return graph[edgetype(graph)(vertices(graph)[edge[1]], vertices(graph)[edge[2]])] + graph::AbstractDataGraph, edge::Pair{<:OrdinalSuffixedInteger, <:OrdinalSuffixedInteger} + ) + return graph[edgetype(graph)(vertices(graph)[edge[1]], vertices(graph)[edge[2]])] end function Base.setindex!(graph::AbstractDataGraph, value, vertex::OrdinalSuffixedInteger) - graph[vertices(graph)[vertex]] = value - return graph + graph[vertices(graph)[vertex]] = value + return graph end function Base.setindex!( - graph::AbstractDataGraph, - value, - edge::Pair{<:OrdinalSuffixedInteger,<:OrdinalSuffixedInteger}, -) - graph[edgetype(graph)(vertices(graph)[edge[1]], vertices(graph)[edge[2]])] = value - return graph + graph::AbstractDataGraph, + value, + edge::Pair{<:OrdinalSuffixedInteger, <:OrdinalSuffixedInteger}, + ) + graph[edgetype(graph)(vertices(graph)[edge[1]], vertices(graph)[edge[2]])] = value + return graph end end diff --git a/src/abstractdatagraph.jl b/src/abstractdatagraph.jl index d6e2612..b944d59 100644 --- a/src/abstractdatagraph.jl +++ b/src/abstractdatagraph.jl @@ -1,22 +1,22 @@ using Dictionaries: set!, unset! using Graphs: - Graphs, - AbstractEdge, - AbstractGraph, - IsDirected, - add_edge!, - a_star, - edges, - ne, - nv, - steiner_tree, - vertices + Graphs, + AbstractEdge, + AbstractGraph, + IsDirected, + add_edge!, + a_star, + edges, + ne, + nv, + steiner_tree, + vertices using NamedGraphs.GraphsExtensions: - GraphsExtensions, arrange_edge, incident_edges, is_edge_arranged, vertextype + GraphsExtensions, arrange_edge, incident_edges, is_edge_arranged, vertextype using NamedGraphs.SimilarType: similar_type using SimpleTraits: SimpleTraits, Not, @traitfn -abstract type AbstractDataGraph{V,VD,ED} <: AbstractGraph{V} end +abstract type AbstractDataGraph{V, VD, ED} <: AbstractGraph{V} end # Minimal interface # TODO: Define for `AbstractGraph` as a `DataGraphInterface`. @@ -29,10 +29,10 @@ edge_data_eltype(::Type{<:AbstractDataGraph}) = not_implemented() # Derived interface function Graphs.edgetype(graph_type::Type{<:AbstractDataGraph}) - return Graphs.edgetype(underlying_graph_type(graph_type)) + return Graphs.edgetype(underlying_graph_type(graph_type)) end function Graphs.is_directed(graph_type::Type{<:AbstractDataGraph}) - return Graphs.is_directed(underlying_graph_type(graph_type)) + return Graphs.is_directed(underlying_graph_type(graph_type)) end underlying_graph_type(graph::AbstractDataGraph) = typeof(underlying_graph(graph)) vertex_data_eltype(graph::AbstractDataGraph) = eltype(vertex_data(graph)) @@ -40,7 +40,7 @@ edge_data_eltype(graph::AbstractDataGraph) = eltype(edge_data(graph)) # TODO: delete, defined for AbstractGraph{V}? function GraphsExtensions.vertextype(graph_type::Type{<:AbstractDataGraph}) - return vertextype(underlying_graph_type(graph_type)) + return vertextype(underlying_graph_type(graph_type)) end GraphsExtensions.vertextype(graph::AbstractDataGraph) = vertextype(typeof(graph)) @@ -48,380 +48,380 @@ Base.zero(graph_type::Type{<:AbstractDataGraph}) = graph_type() # Graphs overloads for f in [ - :(Graphs.a_star), - :(Graphs.add_edge!), - :(Graphs.add_vertex!), - :(Graphs.adjacency_matrix), - :(Graphs.bellman_ford_shortest_paths), - :(Graphs.bfs_parents), - :(Graphs.bfs_tree), - :(Graphs.boruvka_mst), - :(Graphs.center), - :(Graphs.common_neighbors), - :(Graphs.connected_components), - :(Graphs.degree), - :(Graphs.degree_histogram), - :(Graphs.desopo_pape_shortest_paths), - :(Graphs.dfs_parents), - :(Graphs.dfs_tree), - :(Graphs.diameter), - :(Graphs.dijkstra_shortest_paths), - :(Graphs.eccentricity), - :(Graphs.edges), - :(Graphs.edgetype), - :(Graphs.eltype), - :(Graphs.enumerate_paths), - :(Graphs.floyd_warshall_shortest_paths), - :(Graphs.has_edge), - :(Graphs.has_path), - :(Graphs.has_vertex), - :(Graphs.inneighbors), - :(Graphs.is_connected), - :(Graphs.is_cyclic), - :(Graphs.is_directed), - :(Graphs.is_strongly_connected), - :(Graphs.is_weakly_connected), - :(Graphs.mincut), - :(Graphs.ne), - :(Graphs.neighbors), - :(Graphs.neighborhood), - :(Graphs.neighborhood_dists), - :(Graphs.johnson_shortest_paths), - :(Graphs.spfa_shortest_paths), - :(Graphs.yen_k_shortest_paths), - :(Graphs.kruskal_mst), - :(Graphs.prim_mst), - :(Graphs.nv), - :(Graphs.outneighbors), - :(Graphs.periphery), - :(Graphs.radius), - :(Graphs.steiner_tree), - :(Graphs.topological_sort_by_dfs), - :(Graphs.tree), - :(Graphs.vertices), - :(GraphsExtensions.boundary_edges), - :(GraphsExtensions.boundary_vertices), - :(GraphsExtensions.eccentricities), - :(GraphsExtensions.inner_boundary_vertices), - :(GraphsExtensions.mincut_partitions), - :(GraphsExtensions.outer_boundary_vertices), - :(GraphsExtensions.symrcm_perm), - :(GraphsExtensions.symrcm_permute), -] - @eval begin - function $f(graph::AbstractDataGraph, args...; kwargs...) - return $f(underlying_graph(graph), args...; kwargs...) + :(Graphs.a_star), + :(Graphs.add_edge!), + :(Graphs.add_vertex!), + :(Graphs.adjacency_matrix), + :(Graphs.bellman_ford_shortest_paths), + :(Graphs.bfs_parents), + :(Graphs.bfs_tree), + :(Graphs.boruvka_mst), + :(Graphs.center), + :(Graphs.common_neighbors), + :(Graphs.connected_components), + :(Graphs.degree), + :(Graphs.degree_histogram), + :(Graphs.desopo_pape_shortest_paths), + :(Graphs.dfs_parents), + :(Graphs.dfs_tree), + :(Graphs.diameter), + :(Graphs.dijkstra_shortest_paths), + :(Graphs.eccentricity), + :(Graphs.edges), + :(Graphs.edgetype), + :(Graphs.eltype), + :(Graphs.enumerate_paths), + :(Graphs.floyd_warshall_shortest_paths), + :(Graphs.has_edge), + :(Graphs.has_path), + :(Graphs.has_vertex), + :(Graphs.inneighbors), + :(Graphs.is_connected), + :(Graphs.is_cyclic), + :(Graphs.is_directed), + :(Graphs.is_strongly_connected), + :(Graphs.is_weakly_connected), + :(Graphs.mincut), + :(Graphs.ne), + :(Graphs.neighbors), + :(Graphs.neighborhood), + :(Graphs.neighborhood_dists), + :(Graphs.johnson_shortest_paths), + :(Graphs.spfa_shortest_paths), + :(Graphs.yen_k_shortest_paths), + :(Graphs.kruskal_mst), + :(Graphs.prim_mst), + :(Graphs.nv), + :(Graphs.outneighbors), + :(Graphs.periphery), + :(Graphs.radius), + :(Graphs.steiner_tree), + :(Graphs.topological_sort_by_dfs), + :(Graphs.tree), + :(Graphs.vertices), + :(GraphsExtensions.boundary_edges), + :(GraphsExtensions.boundary_vertices), + :(GraphsExtensions.eccentricities), + :(GraphsExtensions.inner_boundary_vertices), + :(GraphsExtensions.mincut_partitions), + :(GraphsExtensions.outer_boundary_vertices), + :(GraphsExtensions.symrcm_perm), + :(GraphsExtensions.symrcm_permute), + ] + @eval begin + function $f(graph::AbstractDataGraph, args...; kwargs...) + return $f(underlying_graph(graph), args...; kwargs...) + end end - end end # Fix for ambiguity error with `AbstractGraph` version function Graphs.degree(graph::AbstractDataGraph, vertex::Integer) - return Graphs.degree(underlying_graph(graph), vertex) + return Graphs.degree(underlying_graph(graph), vertex) end # Fix for ambiguity error with `AbstractGraph` version function Graphs.dijkstra_shortest_paths( - graph::AbstractDataGraph, vertices::Vector{<:Integer} -) - return Graphs.dijkstra_shortest_paths(underlying_graph(graph), vertices) + graph::AbstractDataGraph, vertices::Vector{<:Integer} + ) + return Graphs.dijkstra_shortest_paths(underlying_graph(graph), vertices) end # Fix for ambiguity error with `AbstractGraph` version function Graphs.eccentricity(graph::AbstractDataGraph, distmx::AbstractMatrix) - return Graphs.eccentricity(underlying_graph(graph), distmx) + return Graphs.eccentricity(underlying_graph(graph), distmx) end # Fix for ambiguity error with `AbstractGraph` version function indegree(graph::AbstractDataGraph, vertex::Integer) - return indegree(underlying_graph(graph), vertex) + return indegree(underlying_graph(graph), vertex) end # Fix for ambiguity error with `AbstractGraph` version function outdegree(graph::AbstractDataGraph, vertex::Integer) - return outdegree(underlying_graph(graph), vertex) + return outdegree(underlying_graph(graph), vertex) end # Fix for ambiguity error with `AbstractGraph` version function Graphs.a_star( - graph::AbstractDataGraph, source::Integer, destination::Integer, args... -) - return a_star(underlying_graph(graph), source, destination, args...) + graph::AbstractDataGraph, source::Integer, destination::Integer, args... + ) + return a_star(underlying_graph(graph), source, destination, args...) end # Fix for ambiguity error with `AbstractGraph` version @traitfn function Graphs.steiner_tree( - graph::AbstractDataGraph::(!IsDirected), term_vert::Vector{<:Integer}, args... -) - return steiner_tree(underlying_graph(graph), term_vert, args...) + graph::AbstractDataGraph::(!IsDirected), term_vert::Vector{<:Integer}, args... + ) + return steiner_tree(underlying_graph(graph), term_vert, args...) end @traitfn GraphsExtensions.directed_graph(graph::AbstractDataGraph::IsDirected) = graph reverse_data_direction(graph::AbstractDataGraph, data) = data function reverse_data_direction(graph::AbstractDataGraph, edge::AbstractEdge, data) - return is_edge_arranged(graph, edge) ? data : reverse_data_direction(graph, data) + return is_edge_arranged(graph, edge) ? data : reverse_data_direction(graph, data) end @traitfn function GraphsExtensions.directed_graph(graph::AbstractDataGraph::(!IsDirected)) - digraph = directed_graph(typeof(graph))(directed_graph(underlying_graph(graph))) - for v in vertices(graph) - # TODO: Only loop over `keys(vertex_data(graph))` - if isassigned(graph, v) - digraph[v] = graph[v] + digraph = directed_graph(typeof(graph))(directed_graph(underlying_graph(graph))) + for v in vertices(graph) + # TODO: Only loop over `keys(vertex_data(graph))` + if isassigned(graph, v) + digraph[v] = graph[v] + end end - end - for e in edges(graph) - # TODO: Only loop over `keys(edge_data(graph))` - # TODO: Are these needed? - add_edge!(digraph, e) - add_edge!(digraph, reverse(e)) - if isassigned(graph, e) - digraph[e] = graph[e] - digraph[reverse(e)] = reverse_data_direction(graph, graph[e]) + for e in edges(graph) + # TODO: Only loop over `keys(edge_data(graph))` + # TODO: Are these needed? + add_edge!(digraph, e) + add_edge!(digraph, reverse(e)) + if isassigned(graph, e) + digraph[e] = graph[e] + digraph[reverse(e)] = reverse_data_direction(graph, graph[e]) + end end - end - return digraph + return digraph end function Base.reverse(graph::AbstractDataGraph) - reversed_graph = typeof(graph)(reverse(underlying_graph(graph))) - for v in vertices(graph) - if isassigned(graph, v) - reversed_graph[v] = graph[v] + reversed_graph = typeof(graph)(reverse(underlying_graph(graph))) + for v in vertices(graph) + if isassigned(graph, v) + reversed_graph[v] = graph[v] + end end - end - for e in edges(graph) - if isassigned(graph, e) - reversed_graph[reverse(e)] = graph[e] + for e in edges(graph) + if isassigned(graph, e) + reversed_graph[reverse(e)] = graph[e] + end end - end - return reversed_graph + return reversed_graph end function Graphs.merge_vertices( - graph::AbstractDataGraph, - merge_vertices; - merge_data=(x, y) -> y, - merge_vertex_data=merge_data, - merge_edge_data=merge_data, - kwargs..., -) - underlying_merged_graph = Graphs.merge_vertices(underlying_graph(graph); kwargs...) - return not_implemented() + graph::AbstractDataGraph, + merge_vertices; + merge_data = (x, y) -> y, + merge_vertex_data = merge_data, + merge_edge_data = merge_data, + kwargs..., + ) + underlying_merged_graph = Graphs.merge_vertices(underlying_graph(graph); kwargs...) + return not_implemented() end function Graphs.merge_vertices!( - graph::AbstractDataGraph, - merge_vertices; - merge_data=(x, y) -> y, - merge_vertex_data=merge_data, - merge_edge_data=merge_data, - kwargs..., -) - underlying_merged_graph = copy(underlying_graph(graph)) - Graphs.merge_vertices!(underlying_merged_graph; kwargs...) - return not_implemented() + graph::AbstractDataGraph, + merge_vertices; + merge_data = (x, y) -> y, + merge_vertex_data = merge_data, + merge_edge_data = merge_data, + kwargs..., + ) + underlying_merged_graph = copy(underlying_graph(graph)) + Graphs.merge_vertices!(underlying_merged_graph; kwargs...) + return not_implemented() end # Union the vertices and edges of the graphs and # merge the vertex and edge metadata. function Base.union( - graph1::AbstractDataGraph, - graph2::AbstractDataGraph; - merge_data=(x, y) -> y, - merge_vertex_data=merge_data, - merge_edge_data=merge_data, -) - underlying_graph_union = union(underlying_graph(graph1), underlying_graph(graph2)) - vertex_data_merge = mergewith(merge_vertex_data, vertex_data(graph1), vertex_data(graph2)) - edge_data_merge = mergewith(merge_edge_data, edge_data(graph1), edge_data(graph2)) - # TODO: Convert to `promote_type(typeof(graph1), typeof(graph2))` - return _DataGraph(underlying_graph_union, vertex_data_merge, edge_data_merge) + graph1::AbstractDataGraph, + graph2::AbstractDataGraph; + merge_data = (x, y) -> y, + merge_vertex_data = merge_data, + merge_edge_data = merge_data, + ) + underlying_graph_union = union(underlying_graph(graph1), underlying_graph(graph2)) + vertex_data_merge = mergewith(merge_vertex_data, vertex_data(graph1), vertex_data(graph2)) + edge_data_merge = mergewith(merge_edge_data, edge_data(graph1), edge_data(graph2)) + # TODO: Convert to `promote_type(typeof(graph1), typeof(graph2))` + return _DataGraph(underlying_graph_union, vertex_data_merge, edge_data_merge) end function Base.union( - graph1::AbstractDataGraph, - graph2::AbstractDataGraph, - graph3::AbstractDataGraph, - graphs_tail::AbstractDataGraph...; - kwargs..., -) - return union(union(graph1, graph2; kwargs...), graph3, graphs_tail...; kwargs...) + graph1::AbstractDataGraph, + graph2::AbstractDataGraph, + graph3::AbstractDataGraph, + graphs_tail::AbstractDataGraph...; + kwargs..., + ) + return union(union(graph1, graph2; kwargs...), graph3, graphs_tail...; kwargs...) end function GraphsExtensions.rename_vertices(f::Function, graph::AbstractDataGraph) - renamed_underlying_graph = GraphsExtensions.rename_vertices(f, underlying_graph(graph)) - # TODO: Base the ouput type on `typeof(graph)`, for example: - # convert_vertextype(eltype(renamed_vertices), typeof(graph))(renamed_underlying_graph) - renamed_graph = DataGraph( - renamed_underlying_graph; - vertex_data_eltype=vertex_data_eltype(graph), - edge_data_eltype=edge_data_eltype(graph), - ) - for v in keys(vertex_data(graph)) - renamed_graph[f(v)] = graph[v] - end - for e in keys(edge_data(graph)) - renamed_graph[GraphsExtensions.rename_vertices(f, e)] = graph[e] - end - return renamed_graph + renamed_underlying_graph = GraphsExtensions.rename_vertices(f, underlying_graph(graph)) + # TODO: Base the ouput type on `typeof(graph)`, for example: + # convert_vertextype(eltype(renamed_vertices), typeof(graph))(renamed_underlying_graph) + renamed_graph = DataGraph( + renamed_underlying_graph; + vertex_data_eltype = vertex_data_eltype(graph), + edge_data_eltype = edge_data_eltype(graph), + ) + for v in keys(vertex_data(graph)) + renamed_graph[f(v)] = graph[v] + end + for e in keys(edge_data(graph)) + renamed_graph[GraphsExtensions.rename_vertices(f, e)] = graph[e] + end + return renamed_graph end function Graphs.rem_vertex!(graph::AbstractDataGraph, vertex) - neighbor_edges = incident_edges(graph, vertex) - # unset!(vertex_data(graph), to_vertex(graph, vertex...)) - unset!(vertex_data(graph), vertex) - for neighbor_edge in neighbor_edges - unset!(edge_data(graph), neighbor_edge) - end - Graphs.rem_vertex!(underlying_graph(graph), vertex) - return graph + neighbor_edges = incident_edges(graph, vertex) + # unset!(vertex_data(graph), to_vertex(graph, vertex...)) + unset!(vertex_data(graph), vertex) + for neighbor_edge in neighbor_edges + unset!(edge_data(graph), neighbor_edge) + end + Graphs.rem_vertex!(underlying_graph(graph), vertex) + return graph end function Graphs.rem_edge!(graph::AbstractDataGraph, edge) - unset!(edge_data(graph), edge) - Graphs.rem_edge!(underlying_graph(graph), edge) - return graph + unset!(edge_data(graph), edge) + Graphs.rem_edge!(underlying_graph(graph), 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) + 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...) + 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...) + return Graphs.dfs_tree(underlying_graph(graph), s; kwargs...) end -function map_vertex_data(f, graph::AbstractDataGraph; vertices=nothing) - graph′ = copy(graph) - vs = isnothing(vertices) ? Graphs.vertices(graph) : vertices - for v in vs - graph′[v] = f(graph[v]) - end - return graph′ +function map_vertex_data(f, graph::AbstractDataGraph; vertices = nothing) + graph′ = copy(graph) + vs = isnothing(vertices) ? Graphs.vertices(graph) : vertices + for v in vs + graph′[v] = f(graph[v]) + end + return graph′ end -function map_edge_data(f, graph::AbstractDataGraph; edges=nothing) - graph′ = copy(graph) - es = isnothing(edges) ? Graphs.edges(graph) : edges - for e in es - if isassigned(graph, e) - graph′[e] = f(graph[e]) +function map_edge_data(f, graph::AbstractDataGraph; edges = nothing) + graph′ = copy(graph) + es = isnothing(edges) ? Graphs.edges(graph) : edges + for e in es + if isassigned(graph, e) + graph′[e] = f(graph[e]) + end end - end - return graph′ + return graph′ end -function map_data(f, graph::AbstractDataGraph; vertices=nothing, edges=nothing) - graph = map_vertex_data(f, graph; vertices) - return map_edge_data(f, graph; edges) +function map_data(f, graph::AbstractDataGraph; vertices = nothing, edges = nothing) + graph = map_vertex_data(f, graph; vertices) + return map_edge_data(f, graph; edges) end function Base.getindex(graph::AbstractDataGraph, vertex) - return vertex_data(graph)[vertex] + return vertex_data(graph)[vertex] end function Base.get(graph::AbstractDataGraph, vertex, default) - return get(vertex_data(graph), vertex, default) + return get(vertex_data(graph), vertex, default) end function Base.get!(graph::AbstractDataGraph, vertex, default) - return get!(vertex_data(graph), vertex, default) + return get!(vertex_data(graph), vertex, default) end function Base.getindex(graph::AbstractDataGraph, edge::AbstractEdge) - data = edge_data(graph)[arrange_edge(graph, edge)] - return reverse_data_direction(graph, edge, data) + data = edge_data(graph)[arrange_edge(graph, edge)] + return reverse_data_direction(graph, edge, data) end # Support syntax `g[v1 => v2]` function Base.getindex(graph::AbstractDataGraph, edge::Pair) - return graph[edgetype(graph)(edge)] + return graph[edgetype(graph)(edge)] end function Base.get(graph::AbstractDataGraph, edge::AbstractEdge, default) - data = get(edge_data(graph), arrange_edge(graph, edge), default) - return reverse_data_direction(graph, edge, data) + data = get(edge_data(graph), arrange_edge(graph, edge), default) + return reverse_data_direction(graph, edge, data) end function Base.get(graph::AbstractDataGraph, edge::Pair, default) - return get(graph, edgetype(graph)(edge), default) + return get(graph, edgetype(graph)(edge), default) end function Base.get!(graph::AbstractDataGraph, edge::AbstractEdge, default) - data = get!(edge_data(graph), arrange_edge(graph, edge), default) - return reverse_data_direction(graph, edge, data) + data = get!(edge_data(graph), arrange_edge(graph, edge), default) + return reverse_data_direction(graph, edge, data) end function Base.get!(graph::AbstractDataGraph, edge::Pair, default) - return get!(graph, edgetype(graph)(edge), default) + return get!(graph, edgetype(graph)(edge), default) end # Support syntax `g[1, 2] = g[(1, 2)]` function Base.getindex(graph::AbstractDataGraph, i1, i2, i...) - return graph[(i1, i2, i...)] + return graph[(i1, i2, i...)] end function Base.isassigned(graph::AbstractDataGraph, vertex) - return isassigned(vertex_data(graph), vertex) + return isassigned(vertex_data(graph), vertex) end function Base.isassigned(graph::AbstractDataGraph, edge::AbstractEdge) - return isassigned(edge_data(graph), arrange_edge(graph, edge)) + return isassigned(edge_data(graph), arrange_edge(graph, edge)) end function Base.isassigned(graph::AbstractDataGraph, edge::Pair) - return isassigned(graph, edgetype(graph)(edge)) + return isassigned(graph, edgetype(graph)(edge)) end function Base.setindex!(graph::AbstractDataGraph, data, vertex) - set!(vertex_data(graph), vertex, data) - return graph + set!(vertex_data(graph), vertex, data) + return graph end function Base.setindex!(graph::AbstractDataGraph, data, edge::AbstractEdge) - arranged_edge = arrange_edge(graph, edge) - arranged_data = reverse_data_direction(graph, edge, data) - set!(edge_data(graph), arranged_edge, arranged_data) - return graph + arranged_edge = arrange_edge(graph, edge) + arranged_data = reverse_data_direction(graph, edge, data) + set!(edge_data(graph), arranged_edge, arranged_data) + return graph end function Base.setindex!(graph::AbstractDataGraph, data, edge::Pair) - graph[edgetype(graph)(edge)] = data - return graph + graph[edgetype(graph)(edge)] = data + return graph end # Support syntax `g[1, 2] = g[(1, 2)]` function Base.setindex!(graph::AbstractDataGraph, x, i1, i2, i...) - graph[(i1, i2, i...)] = x - return graph + graph[(i1, i2, i...)] = x + return graph end function Graphs.induced_subgraph(graph::AbstractDataGraph, subvertices) - underlying_subgraph, vlist = Graphs.induced_subgraph(underlying_graph(graph), subvertices) - subgraph = similar_type(graph)(underlying_subgraph) - for v in vertices(subgraph) - if isassigned(graph, v) - subgraph[v] = graph[v] + underlying_subgraph, vlist = Graphs.induced_subgraph(underlying_graph(graph), subvertices) + subgraph = similar_type(graph)(underlying_subgraph) + for v in vertices(subgraph) + if isassigned(graph, v) + subgraph[v] = graph[v] + end end - end - for e in edges(subgraph) - if isassigned(graph, e) - subgraph[e] = graph[e] + for e in edges(subgraph) + if isassigned(graph, e) + subgraph[e] = graph[e] + end end - end - return subgraph, vlist + return subgraph, vlist end # @@ -429,22 +429,22 @@ end # function Base.show(io::IO, mime::MIME"text/plain", graph::AbstractDataGraph) - println(io, "$(typeof(graph)) with $(nv(graph)) vertices:") - show(io, mime, vertices(graph)) - println(io, "\n") - println(io, "and $(ne(graph)) edge(s):") - for e in edges(graph) - show(io, mime, e) + println(io, "$(typeof(graph)) with $(nv(graph)) vertices:") + show(io, mime, vertices(graph)) + println(io, "\n") + println(io, "and $(ne(graph)) edge(s):") + for e in edges(graph) + show(io, mime, e) + println(io) + end + println(io) + println(io, "with vertex data:") + show(io, mime, vertex_data(graph)) + println(io) println(io) - end - println(io) - println(io, "with vertex data:") - show(io, mime, vertex_data(graph)) - println(io) - println(io) - println(io, "and edge data:") - show(io, mime, edge_data(graph)) - return nothing + println(io, "and edge data:") + show(io, mime, edge_data(graph)) + return nothing end Base.show(io::IO, graph::AbstractDataGraph) = show(io, MIME"text/plain"(), graph) diff --git a/src/datagraph.jl b/src/datagraph.jl index 665a1f1..6317224 100644 --- a/src/datagraph.jl +++ b/src/datagraph.jl @@ -8,23 +8,23 @@ using NamedGraphs.GraphsExtensions: convert_vertextype, directed_graph, vertexty # TODO: Use https://github.com/vtjnash/ComputedFieldTypes.jl to # automatically determine `E` from `G` from `edgetype(G)` # and `V` from `G` as `vertextype(G)`. -struct DataGraph{V,VD,ED,G<:AbstractGraph,E<:AbstractEdge} <: AbstractDataGraph{V,VD,ED} - underlying_graph::G - vertex_data::Dictionary{V,VD} - edge_data::Dictionary{E,ED} - global function _DataGraph( - underlying_graph::AbstractGraph, vertex_data::Dictionary, edge_data::Dictionary - ) - return new{ - vertextype(underlying_graph), - eltype(vertex_data), - eltype(edge_data), - typeof(underlying_graph), - edgetype(underlying_graph), - }( - underlying_graph, vertex_data, edge_data - ) - end +struct DataGraph{V, VD, ED, G <: AbstractGraph, E <: AbstractEdge} <: AbstractDataGraph{V, VD, ED} + underlying_graph::G + vertex_data::Dictionary{V, VD} + edge_data::Dictionary{E, ED} + global function _DataGraph( + underlying_graph::AbstractGraph, vertex_data::Dictionary, edge_data::Dictionary + ) + return new{ + vertextype(underlying_graph), + eltype(vertex_data), + eltype(edge_data), + typeof(underlying_graph), + edgetype(underlying_graph), + }( + underlying_graph, vertex_data, edge_data + ) + end end underlying_graph_type(G::Type{<:DataGraph}) = fieldtype(G, :underlying_graph) vertex_data_eltype(G::Type{<:DataGraph}) = eltype(fieldtype(G, :vertex_data)) @@ -39,63 +39,63 @@ Graphs.is_directed(G::Type{<:DataGraph}) = Graphs.is_directed(underlying_graph_t # TODO: Implement in terms of `set_underlying_graph`, `set_vertex_data`, etc. # TODO: Use `https://github.com/JuliaObjects/Accessors.jl`? 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)) - ) + # 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)) + ) end function DataGraph{V}( - underlying_graph::AbstractGraph; vertex_data_eltype::Type=Any, edge_data_eltype::Type=Any -) where {V} - converted_underlying_graph = convert_vertextype(V, underlying_graph) - return _DataGraph( - converted_underlying_graph, - Dictionary{vertextype(converted_underlying_graph),vertex_data_eltype}(), - Dictionary{edgetype(converted_underlying_graph),edge_data_eltype}(), - ) + underlying_graph::AbstractGraph; vertex_data_eltype::Type = Any, edge_data_eltype::Type = Any + ) where {V} + converted_underlying_graph = convert_vertextype(V, underlying_graph) + return _DataGraph( + converted_underlying_graph, + Dictionary{vertextype(converted_underlying_graph), vertex_data_eltype}(), + Dictionary{edgetype(converted_underlying_graph), edge_data_eltype}(), + ) end function DataGraph(underlying_graph::AbstractGraph; kwargs...) - return DataGraph{vertextype(underlying_graph)}(underlying_graph; kwargs...) + return DataGraph{vertextype(underlying_graph)}(underlying_graph; kwargs...) end -function DataGraph{V,VD,ED,G,E}(underlying_graph::AbstractGraph) where {V,VD,ED,G,E} - @assert edgetype(underlying_graph) === E - return _DataGraph(convert(G, underlying_graph), Dictionary{V,VD}(), Dictionary{E,ED}()) +function DataGraph{V, VD, ED, G, E}(underlying_graph::AbstractGraph) where {V, VD, ED, G, E} + @assert edgetype(underlying_graph) === E + return _DataGraph(convert(G, underlying_graph), Dictionary{V, VD}(), Dictionary{E, ED}()) end # Type conversions -DataGraph{V,VD,ED,G}(graph::DataGraph{V,VD,ED,G}) where {V,VD,ED,G} = copy(graph) -DataGraph{V,VD,ED}(graph::DataGraph{V,VD,ED}) where {V,VD,ED} = copy(graph) -DataGraph{V,VD}(graph::DataGraph{V,VD}) where {V,VD} = copy(graph) +DataGraph{V, VD, ED, G}(graph::DataGraph{V, VD, ED, G}) where {V, VD, ED, G} = copy(graph) +DataGraph{V, VD, ED}(graph::DataGraph{V, VD, ED}) where {V, VD, ED} = copy(graph) +DataGraph{V, VD}(graph::DataGraph{V, VD}) where {V, VD} = copy(graph) 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_edge_data = Dictionary( - edgetype(converted_underlying_graph).(keys(edge_data(graph))), values(edge_data(graph)) - ) - return _DataGraph(converted_underlying_graph, converted_vertex_data, converted_edge_data) + # 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_edge_data = Dictionary( + edgetype(converted_underlying_graph).(keys(edge_data(graph))), values(edge_data(graph)) + ) + return _DataGraph(converted_underlying_graph, converted_vertex_data, converted_edge_data) end GraphsExtensions.convert_vertextype(::Type{V}, graph::DataGraph{V}) where {V} = graph function GraphsExtensions.convert_vertextype(vertextype::Type, graph::DataGraph) - return DataGraph{vertextype}(graph) + return DataGraph{vertextype}(graph) end # TODO: implement generic version in terms of `set_underlying_graph_type`. function GraphsExtensions.directed_graph_type(graph_type::Type{<:DataGraph}) - return DataGraph{ - vertextype(graph_type), - vertex_data_eltype(graph_type), - edgetype(graph_type), - directed_graph_type(underlying_graph_type(graph_type)), - edgetype(graph_type), - } + return DataGraph{ + vertextype(graph_type), + vertex_data_eltype(graph_type), + edgetype(graph_type), + directed_graph_type(underlying_graph_type(graph_type)), + edgetype(graph_type), + } end diff --git a/test/runtests.jl b/test/runtests.jl index 98b2d2b..0008050 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,60 +6,62 @@ using Suppressor: Suppressor const pat = r"(?:--group=)(\w+)" arg_id = findfirst(contains(pat), ARGS) const GROUP = uppercase( - if isnothing(arg_id) - get(ENV, "GROUP", "ALL") - else - only(match(pat, ARGS[arg_id]).captures) - end, + if isnothing(arg_id) + get(ENV, "GROUP", "ALL") + else + only(match(pat, ARGS[arg_id]).captures) + end, ) "match files of the form `test_*.jl`, but exclude `*setup*.jl`" function istestfile(fn) - return endswith(fn, ".jl") && startswith(basename(fn), "test_") && !contains(fn, "setup") + return endswith(fn, ".jl") && startswith(basename(fn), "test_") && !contains(fn, "setup") end "match files of the form `*.jl`, but exclude `*_notest.jl` and `*setup*.jl`" function isexamplefile(fn) - return endswith(fn, ".jl") && !endswith(fn, "_notest.jl") && !contains(fn, "setup") + return endswith(fn, ".jl") && !endswith(fn, "_notest.jl") && !contains(fn, "setup") end @time begin - # tests in groups based on folder structure - for testgroup in filter(isdir, readdir(@__DIR__)) - if GROUP == "ALL" || GROUP == uppercase(testgroup) - groupdir = joinpath(@__DIR__, testgroup) - for file in filter(istestfile, readdir(groupdir)) - filename = joinpath(groupdir, file) - @eval @safetestset $file begin - include($filename) + # tests in groups based on folder structure + for testgroup in filter(isdir, readdir(@__DIR__)) + if GROUP == "ALL" || GROUP == uppercase(testgroup) + groupdir = joinpath(@__DIR__, testgroup) + for file in filter(istestfile, readdir(groupdir)) + filename = joinpath(groupdir, file) + @eval @safetestset $file begin + include($filename) + end + end end - end end - end - # single files in top folder - for file in filter(istestfile, readdir(@__DIR__)) - (file == basename(@__FILE__)) && continue # exclude this file to avoid infinite recursion - @eval @safetestset $file begin - include($file) + # single files in top folder + for file in filter(istestfile, readdir(@__DIR__)) + (file == basename(@__FILE__)) && continue # exclude this file to avoid infinite recursion + @eval @safetestset $file begin + include($file) + end end - end - # test examples - examplepath = joinpath(@__DIR__, "..", "examples") - for (root, _, files) in walkdir(examplepath) - contains(chopprefix(root, @__DIR__), "setup") && continue - for file in filter(isexamplefile, files) - filename = joinpath(root, file) - @eval begin - @safetestset $file begin - $(Expr( - :macrocall, - GlobalRef(Suppressor, Symbol("@suppress")), - LineNumberNode(@__LINE__, @__FILE__), - :(include($filename)), - )) + # test examples + examplepath = joinpath(@__DIR__, "..", "examples") + for (root, _, files) in walkdir(examplepath) + contains(chopprefix(root, @__DIR__), "setup") && continue + for file in filter(isexamplefile, files) + filename = joinpath(root, file) + @eval begin + @safetestset $file begin + $( + Expr( + :macrocall, + GlobalRef(Suppressor, Symbol("@suppress")), + LineNumberNode(@__LINE__, @__FILE__), + :(include($filename)), + ) + ) + end + end end - end end - end end diff --git a/test/test_aqua.jl b/test/test_aqua.jl index 8dad0e7..c23ed74 100644 --- a/test/test_aqua.jl +++ b/test/test_aqua.jl @@ -3,5 +3,5 @@ using DataGraphs: DataGraphs using Test: @testset @testset "Code quality (Aqua.jl)" begin - # Aqua.test_all(DataGraphs) + # Aqua.test_all(DataGraphs) end diff --git a/test/test_basics.jl b/test/test_basics.jl index 427cf63..31556b5 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -1,28 +1,28 @@ using DataGraphs: - DataGraphs, DataGraph, edge_data, edge_data_eltype, vertex_data, vertex_data_eltype + DataGraphs, DataGraph, edge_data, edge_data_eltype, vertex_data, vertex_data_eltype using Dictionaries: AbstractIndices, Dictionary, Indices, dictionary using Graphs: - add_edge!, - a_star, - 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 + add_edge!, + a_star, + 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.SimpleGraphs: SimpleDiGraph, SimpleEdge, SimpleGraph using GraphsFlows: GraphsFlows using NamedGraphs: NamedDiGraph, NamedEdge, NamedGraph @@ -32,406 +32,406 @@ using NamedGraphs.OrdinalIndexing: nd, st, rd, th using Test: @test, @test_broken, @testset @testset "DataGraphs.jl" begin - @eval module $(gensym()) - using DataGraphs: DataGraphs - using Suppressor: @suppress - using Test: @testset - @testset "Examples" begin - examples_path = joinpath(pkgdir(DataGraphs), "examples") - @testset "Run examples: $filename" for filename in readdir(examples_path) - if endswith(filename, ".jl") - @suppress include(joinpath(examples_path, filename)) - end + @eval module $(gensym()) + using DataGraphs: DataGraphs + using Suppressor: @suppress + using Test: @testset + @testset "Examples" begin + examples_path = joinpath(pkgdir(DataGraphs), "examples") + @testset "Run examples: $filename" for filename in readdir(examples_path) + if endswith(filename, ".jl") + @suppress include(joinpath(examples_path, filename)) + end + end end - end - end - - @testset "Basics" begin - g = grid((4,)) - dg = DataGraph(g; vertex_data_eltype=String, edge_data_eltype=Symbol) - @test !isassigned(dg, SimpleEdge(1, 2)) - @test !isassigned(dg, 1 => 2) - @test !isassigned(dg, SimpleEdge(1 => 2)) - @test !isassigned(dg, 1 => 3) - @test !isassigned(dg, 1) - @test !isassigned(dg, 2) - @test !isassigned(dg, 3) - @test !isassigned(dg, 4) - - @test degree(g, 1) == 1 - @test indegree(g, 1) == 1 - @test outdegree(g, 1) == 1 - @test degree(g, 2) == 2 - @test indegree(g, 2) == 2 - @test outdegree(g, 2) == 2 - - @test has_edge(dg, 1, 2) - @test has_edge(dg, 1 => 2) - @test !has_edge(dg, 1, 3) - @test !has_edge(dg, 1 => 3) - @test has_vertex(dg, 1) - @test has_vertex(dg, 4) - @test !has_vertex(dg, 0) - @test !has_vertex(dg, 5) - - dg[1] = "V1" - dg[2] = "V2" - dg[3] = "V3" - dg[4] = "V4" - @test isassigned(dg, 1) - @test dg[1] == "V1" - @test dg[2] == "V2" - @test dg[3] == "V3" - @test dg[4] == "V4" - - dg[1 => 2] = :E12 - dg[2 => 3] = :E23 - dg[SimpleEdge(3, 4)] = :E34 - #@test isassigned(dg, (1, 2)) - @test isassigned(dg, SimpleEdge(2, 3)) - @test isassigned(dg, 3 => 4) - @test dg[SimpleEdge(1, 2)] == :E12 - @test dg[2 => 3] == :E23 - @test dg[3 => 4] == :E34 - - # Regression test - # g = NamedGraph([(1, 1), (1, (1, 1))]) - dg = DataGraph(NamedGraph([(1, 1), (1, (1, 1))])) - dg[(1, 1) => (1, (1, 1))] = "X" - @test dg[(1, 1) => (1, (1, 1))] == "X" - - vdata = map(v -> "V$v", Indices(1:4)) - edata = map(e -> "E$(src(e))$(dst(e))", Indices(SimpleEdge.([1 => 2, 2 => 3, 3 => 4]))) - # TODO: Make a more compact constructor that directly accepts - # vertex and edge data? Maybe `DataGraph(g; vertex_data=vdata, edge_data=edata)` - # or `DataGraph(g; vertex_data=v -> "V$v", edge_data=e -> "E$(src(e))$(dst(e))")`. - dg = DataGraph(g; vertex_data_eltype=eltype(vdata), edge_data_eltype=eltype(edata)) - for v in vertices(dg) - dg[v] = vdata[v] end - for e in edges(dg) - dg[e] = edata[e] + + @testset "Basics" begin + g = grid((4,)) + dg = DataGraph(g; vertex_data_eltype = String, edge_data_eltype = Symbol) + @test !isassigned(dg, SimpleEdge(1, 2)) + @test !isassigned(dg, 1 => 2) + @test !isassigned(dg, SimpleEdge(1 => 2)) + @test !isassigned(dg, 1 => 3) + @test !isassigned(dg, 1) + @test !isassigned(dg, 2) + @test !isassigned(dg, 3) + @test !isassigned(dg, 4) + + @test degree(g, 1) == 1 + @test indegree(g, 1) == 1 + @test outdegree(g, 1) == 1 + @test degree(g, 2) == 2 + @test indegree(g, 2) == 2 + @test outdegree(g, 2) == 2 + + @test has_edge(dg, 1, 2) + @test has_edge(dg, 1 => 2) + @test !has_edge(dg, 1, 3) + @test !has_edge(dg, 1 => 3) + @test has_vertex(dg, 1) + @test has_vertex(dg, 4) + @test !has_vertex(dg, 0) + @test !has_vertex(dg, 5) + + dg[1] = "V1" + dg[2] = "V2" + dg[3] = "V3" + dg[4] = "V4" + @test isassigned(dg, 1) + @test dg[1] == "V1" + @test dg[2] == "V2" + @test dg[3] == "V3" + @test dg[4] == "V4" + + dg[1 => 2] = :E12 + dg[2 => 3] = :E23 + dg[SimpleEdge(3, 4)] = :E34 + #@test isassigned(dg, (1, 2)) + @test isassigned(dg, SimpleEdge(2, 3)) + @test isassigned(dg, 3 => 4) + @test dg[SimpleEdge(1, 2)] == :E12 + @test dg[2 => 3] == :E23 + @test dg[3 => 4] == :E34 + + # Regression test + # g = NamedGraph([(1, 1), (1, (1, 1))]) + dg = DataGraph(NamedGraph([(1, 1), (1, (1, 1))])) + dg[(1, 1) => (1, (1, 1))] = "X" + @test dg[(1, 1) => (1, (1, 1))] == "X" + + vdata = map(v -> "V$v", Indices(1:4)) + edata = map(e -> "E$(src(e))$(dst(e))", Indices(SimpleEdge.([1 => 2, 2 => 3, 3 => 4]))) + # TODO: Make a more compact constructor that directly accepts + # vertex and edge data? Maybe `DataGraph(g; vertex_data=vdata, edge_data=edata)` + # or `DataGraph(g; vertex_data=v -> "V$v", edge_data=e -> "E$(src(e))$(dst(e))")`. + dg = DataGraph(g; vertex_data_eltype = eltype(vdata), edge_data_eltype = eltype(edata)) + for v in vertices(dg) + dg[v] = vdata[v] + end + for e in edges(dg) + dg[e] = edata[e] + end + + @test dg[1] == "V1" + @test dg[2] == "V2" + @test dg[3] == "V3" + @test dg[4] == "V4" + @test dg[1 => 2] == "E12" + @test dg[2 => 3] == "E23" + @test dg[3 => 4] == "E34" + + @test DataGraph(g) isa DataGraph{Int, Any, Any, SimpleGraph{Int}, SimpleEdge{Int}} + + dg_uint16 = DataGraph{UInt16}(dg) + @test dg_uint16 isa + DataGraph{UInt16, String, String, SimpleGraph{UInt16}, SimpleEdge{UInt16}} + @test vertextype(dg_uint16) === UInt16 + @test edgetype(dg_uint16) === SimpleEdge{UInt16} + @test vertex_data_eltype(dg_uint16) === String + @test edge_data_eltype(dg_uint16) === String + @test dg_uint16[1] == "V1" + @test dg_uint16[2] == "V2" + @test dg_uint16[3] == "V3" + @test dg_uint16[4] == "V4" + @test dg_uint16[1 => 2] == "E12" + @test dg_uint16[2 => 3] == "E23" + @test dg_uint16[3 => 4] == "E34" + + # Vertices with mixed types + dg = DataGraph(NamedGraph(grid((4,)), [1, "X", 2, "Y"])) + @test nv(dg) == 4 + @test ne(dg) == 3 + dg[1] = "vertex_1" + dg["X"] = "vertex_X" + dg[2] = "vertex_2" + dg["Y"] = "vertex_Y" + @test dg[1] == "vertex_1" + @test dg["X"] == "vertex_X" + @test dg[2] == "vertex_2" + @test dg["Y"] == "vertex_Y" + + dg[1 => "X"] = "edge_1X" + dg["X" => 2] = "edge_X2" + dg[2 => "Y"] = "edge_2Y" + @test dg[1 => "X"] == "edge_1X" + @test dg["X" => 1] == "edge_1X" + @test dg["X" => 2] == "edge_X2" + @test dg[2 => "X"] == "edge_X2" + @test dg[2 => "Y"] == "edge_2Y" + @test dg["Y" => 2] == "edge_2Y" + + dg["X" => 1] = "edge_X1" + dg[2 => "X"] = "edge_2X" + dg["Y" => 2] = "edge_Y2" + @test dg[1 => "X"] == "edge_X1" + @test dg["X" => 1] == "edge_X1" + @test dg["X" => 2] == "edge_2X" + @test dg[2 => "X"] == "edge_2X" + @test dg[2 => "Y"] == "edge_Y2" + @test dg["Y" => 2] == "edge_Y2" end - @test dg[1] == "V1" - @test dg[2] == "V2" - @test dg[3] == "V3" - @test dg[4] == "V4" - @test dg[1 => 2] == "E12" - @test dg[2 => 3] == "E23" - @test dg[3 => 4] == "E34" - - @test DataGraph(g) isa DataGraph{Int,Any,Any,SimpleGraph{Int},SimpleEdge{Int}} - - dg_uint16 = DataGraph{UInt16}(dg) - @test dg_uint16 isa - DataGraph{UInt16,String,String,SimpleGraph{UInt16},SimpleEdge{UInt16}} - @test vertextype(dg_uint16) === UInt16 - @test edgetype(dg_uint16) === SimpleEdge{UInt16} - @test vertex_data_eltype(dg_uint16) === String - @test edge_data_eltype(dg_uint16) === String - @test dg_uint16[1] == "V1" - @test dg_uint16[2] == "V2" - @test dg_uint16[3] == "V3" - @test dg_uint16[4] == "V4" - @test dg_uint16[1 => 2] == "E12" - @test dg_uint16[2 => 3] == "E23" - @test dg_uint16[3 => 4] == "E34" - - # Vertices with mixed types - dg = DataGraph(NamedGraph(grid((4,)), [1, "X", 2, "Y"])) - @test nv(dg) == 4 - @test ne(dg) == 3 - dg[1] = "vertex_1" - dg["X"] = "vertex_X" - dg[2] = "vertex_2" - dg["Y"] = "vertex_Y" - @test dg[1] == "vertex_1" - @test dg["X"] == "vertex_X" - @test dg[2] == "vertex_2" - @test dg["Y"] == "vertex_Y" - - dg[1 => "X"] = "edge_1X" - dg["X" => 2] = "edge_X2" - dg[2 => "Y"] = "edge_2Y" - @test dg[1 => "X"] == "edge_1X" - @test dg["X" => 1] == "edge_1X" - @test dg["X" => 2] == "edge_X2" - @test dg[2 => "X"] == "edge_X2" - @test dg[2 => "Y"] == "edge_2Y" - @test dg["Y" => 2] == "edge_2Y" - - dg["X" => 1] = "edge_X1" - dg[2 => "X"] = "edge_2X" - dg["Y" => 2] = "edge_Y2" - @test dg[1 => "X"] == "edge_X1" - @test dg["X" => 1] == "edge_X1" - @test dg["X" => 2] == "edge_2X" - @test dg[2 => "X"] == "edge_2X" - @test dg[2 => "Y"] == "edge_Y2" - @test dg["Y" => 2] == "edge_Y2" - end - - @testset "get and get! functions" begin - g = grid((4,)) - dg = DataGraph(g; vertex_data_eltype=String, edge_data_eltype=Symbol) - - # Test for vertices - @test get(dg, 1, "default") == "default" - @test !isassigned(dg, 1) - - @test get!(dg, 2, "default") == "default" - @test isassigned(dg, 2) - @test dg[2] == "default" - - # Test for edges - @test get(dg, 1 => 2, :default) == :default - @test !isassigned(dg, 1 => 2) - - @test get!(dg, 1 => 2, :default) == :default - @test isassigned(dg, 1 => 2) - @test dg[1 => 2] == :default - end - - @testset "Constructors specifying vertex type" begin - dg = DataGraph{Float64}( - named_path_graph(4); vertex_data_eltype=String, edge_data_eltype=Symbol - ) - @test nv(dg) == 4 - @test ne(dg) == 3 - @test edgetype(dg) === NamedEdge{Float64} - @test vertextype(dg) === Float64 - @test vertex_data_eltype(dg) === String - @test edge_data_eltype(dg) === Symbol - @test issetequal(vertices(dg), Float64.(1:4)) - @test vertices(dg) isa AbstractIndices{Float64} - @test eltype(vertices(dg)) === Float64 - @test has_edge(dg, 1.0 => 2.0) - @test has_edge(dg, 2.0 => 3.0) - @test has_edge(dg, 3.0 => 4.0) - @test vertex_data(dg) == Dictionary{Float64,String}() - @test vertex_data(dg) isa Dictionary{Float64,String} - @test keytype(vertex_data(dg)) === Float64 - @test eltype(vertex_data(dg)) === String - @test edge_data(dg) == Dictionary{NamedEdge{Float64},Symbol}() - @test edge_data(dg) isa Dictionary{NamedEdge{Float64},Symbol} - @test keytype(edge_data(dg)) === NamedEdge{Float64} - @test eltype(edge_data(dg)) === Symbol - end - - @testset "Disjoint unions" begin - g = DataGraph(named_grid((2, 2)); vertex_data_eltype=String, edge_data_eltype=String) - - for v in vertices(g) - g[v] = "V$v" + @testset "get and get! functions" begin + g = grid((4,)) + dg = DataGraph(g; vertex_data_eltype = String, edge_data_eltype = Symbol) + + # Test for vertices + @test get(dg, 1, "default") == "default" + @test !isassigned(dg, 1) + + @test get!(dg, 2, "default") == "default" + @test isassigned(dg, 2) + @test dg[2] == "default" + + # Test for edges + @test get(dg, 1 => 2, :default) == :default + @test !isassigned(dg, 1 => 2) + + @test get!(dg, 1 => 2, :default) == :default + @test isassigned(dg, 1 => 2) + @test dg[1 => 2] == :default end - for e in edges(g) - g[e] = "E$e" + + @testset "Constructors specifying vertex type" begin + dg = DataGraph{Float64}( + named_path_graph(4); vertex_data_eltype = String, edge_data_eltype = Symbol + ) + @test nv(dg) == 4 + @test ne(dg) == 3 + @test edgetype(dg) === NamedEdge{Float64} + @test vertextype(dg) === Float64 + @test vertex_data_eltype(dg) === String + @test edge_data_eltype(dg) === Symbol + @test issetequal(vertices(dg), Float64.(1:4)) + @test vertices(dg) isa AbstractIndices{Float64} + @test eltype(vertices(dg)) === Float64 + @test has_edge(dg, 1.0 => 2.0) + @test has_edge(dg, 2.0 => 3.0) + @test has_edge(dg, 3.0 => 4.0) + @test vertex_data(dg) == Dictionary{Float64, String}() + @test vertex_data(dg) isa Dictionary{Float64, String} + @test keytype(vertex_data(dg)) === Float64 + @test eltype(vertex_data(dg)) === String + @test edge_data(dg) == Dictionary{NamedEdge{Float64}, Symbol}() + @test edge_data(dg) isa Dictionary{NamedEdge{Float64}, Symbol} + @test keytype(edge_data(dg)) === NamedEdge{Float64} + @test eltype(edge_data(dg)) === Symbol + end + + @testset "Disjoint unions" begin + g = DataGraph(named_grid((2, 2)); vertex_data_eltype = String, edge_data_eltype = String) + + for v in vertices(g) + g[v] = "V$v" + end + for e in edges(g) + g[e] = "E$e" + end + + gg = g ⊔ g + + @test has_vertex(gg, ((1, 1), 1)) + @test has_vertex(gg, ((1, 1), 2)) + @test has_edge(gg, ((1, 1), 1) => ((1, 2), 1)) + @test has_edge(gg, ((1, 1), 2) => ((1, 2), 2)) + @test nv(gg) == 2nv(g) + @test ne(gg) == 2ne(g) + + # TODO: Define `vcat`, `hcat`, `hvncat`? + gg = [g; g] + + @test_broken has_vertex(gg, (1, 1)) + @test_broken has_vertex(gg, (2, 1)) + @test_broken has_vertex(gg, (3, 1)) + @test_broken has_vertex(gg, (4, 1)) + @test_broken has_edge(gg, (1, 1) => (1, 2)) + @test_broken has_edge(gg, (3, 1) => (3, 2)) + @test_broken nv(gg) == 2nv(g) + @test_broken ne(gg) == 2ne(g) + + gg = [g;; g] + + @test_broken has_vertex(gg, (1, 1)) + @test_broken has_vertex(gg, (1, 2)) + @test_broken has_vertex(gg, (1, 3)) + @test_broken has_vertex(gg, (1, 4)) + @test_broken has_edge(gg, (1, 1) => (1, 2)) + @test_broken has_edge(gg, (1, 3) => (1, 4)) + @test_broken nv(gg) == 2nv(g) + @test_broken ne(gg) == 2ne(g) end - gg = g ⊔ g - - @test has_vertex(gg, ((1, 1), 1)) - @test has_vertex(gg, ((1, 1), 2)) - @test has_edge(gg, ((1, 1), 1) => ((1, 2), 1)) - @test has_edge(gg, ((1, 1), 2) => ((1, 2), 2)) - @test nv(gg) == 2nv(g) - @test ne(gg) == 2ne(g) - - # TODO: Define `vcat`, `hcat`, `hvncat`? - gg = [g; g] - - @test_broken has_vertex(gg, (1, 1)) - @test_broken has_vertex(gg, (2, 1)) - @test_broken has_vertex(gg, (3, 1)) - @test_broken has_vertex(gg, (4, 1)) - @test_broken has_edge(gg, (1, 1) => (1, 2)) - @test_broken has_edge(gg, (3, 1) => (3, 2)) - @test_broken nv(gg) == 2nv(g) - @test_broken ne(gg) == 2ne(g) - - gg = [g;; g] - - @test_broken has_vertex(gg, (1, 1)) - @test_broken has_vertex(gg, (1, 2)) - @test_broken has_vertex(gg, (1, 3)) - @test_broken has_vertex(gg, (1, 4)) - @test_broken has_edge(gg, (1, 1) => (1, 2)) - @test_broken has_edge(gg, (1, 3) => (1, 4)) - @test_broken nv(gg) == 2nv(g) - @test_broken ne(gg) == 2ne(g) - end - - @testset "union" begin - g1 = DataGraph(grid((4,))) - g1[1] = ["A", "B", "C"] - g1[1 => 2] = ["E", "F"] - - g2 = DataGraph(SimpleGraph(5)) - add_edge!(g2, 1 => 5) - g2[1] = ["C", "D", "E"] - - # Same as: - # union(g1, g2; merge_data=(x, y) -> y) - g = union(g1, g2) - @test nv(g) == 5 - @test ne(g) == 4 - @test has_edge(g, 1 => 2) - @test has_edge(g, 2 => 3) - @test has_edge(g, 3 => 4) - @test has_edge(g, 1 => 5) - @test g[1] == ["C", "D", "E"] - @test g[1 => 2] == ["E", "F"] - - g = union(g1, g2; merge_data=union) - @test nv(g) == 5 - @test ne(g) == 4 - @test has_edge(g, 1 => 2) - @test has_edge(g, 2 => 3) - @test has_edge(g, 3 => 4) - @test has_edge(g, 1 => 5) - @test g[1] == ["A", "B", "C", "D", "E"] - @test g[1 => 2] == ["E", "F"] - end - @testset "connected_components" begin - g1 = named_path_graph(3) - g2 = rename_vertices(v -> nv(g1) + v, g1) - dg1 = DataGraph(g1) - dg1[1] = "A1" - dg1[2] = "B1" - dg1[3] = "C1" - dg1[1 => 2] = "A1" => "B1" - dg1[2 => 3] = "B1" => "C1" - dg2 = DataGraph(g2) - dg2[1] = "A2" - dg2[2] = "B2" - dg2[3] = "C2" - dg2[1 => 2] = "A2" => "B2" - dg2[2 => 3] = "B2" => "C2" - dg = union(dg1, dg2) - comps = connected_components(dg) - @test length(comps) == 2 - @test issetequal(comps[1], [1, 2, 3]) - @test issetequal(comps[2], [4, 5, 6]) - end - @testset "reverse" begin - g = DataGraph(SimpleDiGraph(4)) - add_edge!(g, 1 => 2) - add_edge!(g, 3 => 4) - g[1 => 2] = :A - g[3 => 4] = "X" - rg = reverse(g) - @test has_edge(rg, 2 => 1) - @test has_edge(rg, 4 => 3) - @test rg[2 => 1] == :A - @test isassigned(rg, 2 => 1) - @test !isassigned(rg, 1 => 2) - @test rg[4 => 3] == "X" - @test !isassigned(rg, 3 => 4) - @test isassigned(rg, 4 => 3) - end - @testset "Tree traversal" begin - g = DataGraph(named_grid(4)) - - t = bfs_tree(g, 2) - es = [2 => 1, 2 => 3, 3 => 4] - @test 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 nv(t) == nv(g) - @test ne(t) == nv(g) - 1 - @test all(e -> has_edge(t, e), es) - - g = DataGraph(named_grid((4, 2))) - - t = bfs_tree(g, (1, 1)) - es = [ - (1, 1) => (1, 2), - (1, 1) => (2, 1), - (2, 1) => (2, 2), - (2, 1) => (3, 1), - (3, 1) => (3, 2), - (3, 1) => (4, 1), - (4, 1) => (4, 2), - ] - @test t isa NamedDiGraph{Tuple{Int,Int}} - @test nv(t) == nv(g) - @test ne(t) == nv(g) - 1 - @test all(e -> has_edge(t, e), es) - - t = dfs_tree(g, (1, 1)) - es = [ - (1, 1) => (2, 1), - (2, 1) => (3, 1), - (3, 1) => (4, 1), - (4, 1) => (4, 2), - (4, 2) => (3, 2), - (3, 2) => (2, 2), - (2, 2) => (1, 2), - ] - @test t isa NamedDiGraph{Tuple{Int,Int}} - @test nv(t) == nv(g) - @test ne(t) == nv(g) - 1 - @test all(e -> has_edge(t, e), es) - end - @testset "dijkstra_shortest_paths" begin - g = DataGraph(named_grid(4)) - ps = dijkstra_shortest_paths(g, [1]) - @test ps.dists == dictionary([1 => 0, 2 => 1, 3 => 2, 4 => 3]) - @test ps.parents == dictionary([1 => 1, 2 => 1, 3 => 2, 4 => 3]) - @test ps.pathcounts == dictionary([1 => 1.0, 2 => 1.0, 3 => 1.0, 4 => 1.0]) - end - @testset "a_star" begin - g = DataGraph(named_grid(4)) - path = a_star(g, 1, 3) - @test path == NamedEdge.([1 => 2, 2 => 3]) - end - @testset "steiner_tree" begin - g = DataGraph(named_grid(5)) - t = steiner_tree(g, [2, 4]) - @test nv(t) == 3 - @test ne(t) == 2 - end - @testset "GraphsFlows.mincut (vertextype=$(eltype(verts))" for verts in ( - [1, 2, 3, 4], ["A", "B", "C", "D"] - ) - g = DataGraph(NamedGraph(path_graph(4), verts)) - part1, part2, flow = GraphsFlows.mincut(g, verts[1], verts[4]) - @test verts[1] ∈ part1 - @test verts[4] ∈ part2 - @test flow == 1 - end - @testset "OrdinalIndexing" begin - g = DataGraph( - NamedGraph(path_graph(3), ["a", "b", "c"]); - vertex_data_eltype=String, - edge_data_eltype=Symbol, - ) - g[1st] = "v_a" - g[2nd] = "v_b" - g[3rd] = "v_c" - g[1st => 2nd] = :e_ab - g[2nd => 3rd] = :e_bc - @test g["a"] == "v_a" - @test g["b"] == "v_b" - @test g["c"] == "v_c" - @test g["a" => "b"] === :e_ab - @test g["b" => "a"] === :e_ab - @test g["b" => "c"] === :e_bc - @test g["c" => "b"] === :e_bc - @test g[1st] == "v_a" - @test g[1th] == "v_a" - @test g[2nd] == "v_b" - @test g[2th] == "v_b" - @test g[3rd] == "v_c" - @test g[3th] == "v_c" - @test g[1st => 2nd] === :e_ab - @test g[2nd => 1st] === :e_ab - @test g[2nd => 3rd] === :e_bc - @test g[3rd => 2nd] === :e_bc - end + @testset "union" begin + g1 = DataGraph(grid((4,))) + g1[1] = ["A", "B", "C"] + g1[1 => 2] = ["E", "F"] + + g2 = DataGraph(SimpleGraph(5)) + add_edge!(g2, 1 => 5) + g2[1] = ["C", "D", "E"] + + # Same as: + # union(g1, g2; merge_data=(x, y) -> y) + g = union(g1, g2) + @test nv(g) == 5 + @test ne(g) == 4 + @test has_edge(g, 1 => 2) + @test has_edge(g, 2 => 3) + @test has_edge(g, 3 => 4) + @test has_edge(g, 1 => 5) + @test g[1] == ["C", "D", "E"] + @test g[1 => 2] == ["E", "F"] + + g = union(g1, g2; merge_data = union) + @test nv(g) == 5 + @test ne(g) == 4 + @test has_edge(g, 1 => 2) + @test has_edge(g, 2 => 3) + @test has_edge(g, 3 => 4) + @test has_edge(g, 1 => 5) + @test g[1] == ["A", "B", "C", "D", "E"] + @test g[1 => 2] == ["E", "F"] + end + @testset "connected_components" begin + g1 = named_path_graph(3) + g2 = rename_vertices(v -> nv(g1) + v, g1) + dg1 = DataGraph(g1) + dg1[1] = "A1" + dg1[2] = "B1" + dg1[3] = "C1" + dg1[1 => 2] = "A1" => "B1" + dg1[2 => 3] = "B1" => "C1" + dg2 = DataGraph(g2) + dg2[1] = "A2" + dg2[2] = "B2" + dg2[3] = "C2" + dg2[1 => 2] = "A2" => "B2" + dg2[2 => 3] = "B2" => "C2" + dg = union(dg1, dg2) + comps = connected_components(dg) + @test length(comps) == 2 + @test issetequal(comps[1], [1, 2, 3]) + @test issetequal(comps[2], [4, 5, 6]) + end + @testset "reverse" begin + g = DataGraph(SimpleDiGraph(4)) + add_edge!(g, 1 => 2) + add_edge!(g, 3 => 4) + g[1 => 2] = :A + g[3 => 4] = "X" + rg = reverse(g) + @test has_edge(rg, 2 => 1) + @test has_edge(rg, 4 => 3) + @test rg[2 => 1] == :A + @test isassigned(rg, 2 => 1) + @test !isassigned(rg, 1 => 2) + @test rg[4 => 3] == "X" + @test !isassigned(rg, 3 => 4) + @test isassigned(rg, 4 => 3) + end + @testset "Tree traversal" begin + g = DataGraph(named_grid(4)) + + t = bfs_tree(g, 2) + es = [2 => 1, 2 => 3, 3 => 4] + @test 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 nv(t) == nv(g) + @test ne(t) == nv(g) - 1 + @test all(e -> has_edge(t, e), es) + + g = DataGraph(named_grid((4, 2))) + + t = bfs_tree(g, (1, 1)) + es = [ + (1, 1) => (1, 2), + (1, 1) => (2, 1), + (2, 1) => (2, 2), + (2, 1) => (3, 1), + (3, 1) => (3, 2), + (3, 1) => (4, 1), + (4, 1) => (4, 2), + ] + @test t isa NamedDiGraph{Tuple{Int, Int}} + @test nv(t) == nv(g) + @test ne(t) == nv(g) - 1 + @test all(e -> has_edge(t, e), es) + + t = dfs_tree(g, (1, 1)) + es = [ + (1, 1) => (2, 1), + (2, 1) => (3, 1), + (3, 1) => (4, 1), + (4, 1) => (4, 2), + (4, 2) => (3, 2), + (3, 2) => (2, 2), + (2, 2) => (1, 2), + ] + @test t isa NamedDiGraph{Tuple{Int, Int}} + @test nv(t) == nv(g) + @test ne(t) == nv(g) - 1 + @test all(e -> has_edge(t, e), es) + end + @testset "dijkstra_shortest_paths" begin + g = DataGraph(named_grid(4)) + ps = dijkstra_shortest_paths(g, [1]) + @test ps.dists == dictionary([1 => 0, 2 => 1, 3 => 2, 4 => 3]) + @test ps.parents == dictionary([1 => 1, 2 => 1, 3 => 2, 4 => 3]) + @test ps.pathcounts == dictionary([1 => 1.0, 2 => 1.0, 3 => 1.0, 4 => 1.0]) + end + @testset "a_star" begin + g = DataGraph(named_grid(4)) + path = a_star(g, 1, 3) + @test path == NamedEdge.([1 => 2, 2 => 3]) + end + @testset "steiner_tree" begin + g = DataGraph(named_grid(5)) + t = steiner_tree(g, [2, 4]) + @test nv(t) == 3 + @test ne(t) == 2 + end + @testset "GraphsFlows.mincut (vertextype=$(eltype(verts))" for verts in ( + [1, 2, 3, 4], ["A", "B", "C", "D"], + ) + g = DataGraph(NamedGraph(path_graph(4), verts)) + part1, part2, flow = GraphsFlows.mincut(g, verts[1], verts[4]) + @test verts[1] ∈ part1 + @test verts[4] ∈ part2 + @test flow == 1 + end + @testset "OrdinalIndexing" begin + g = DataGraph( + NamedGraph(path_graph(3), ["a", "b", "c"]); + vertex_data_eltype = String, + edge_data_eltype = Symbol, + ) + g[1st] = "v_a" + g[2nd] = "v_b" + g[3rd] = "v_c" + g[1st => 2nd] = :e_ab + g[2nd => 3rd] = :e_bc + @test g["a"] == "v_a" + @test g["b"] == "v_b" + @test g["c"] == "v_c" + @test g["a" => "b"] === :e_ab + @test g["b" => "a"] === :e_ab + @test g["b" => "c"] === :e_bc + @test g["c" => "b"] === :e_bc + @test g[1st] == "v_a" + @test g[1th] == "v_a" + @test g[2nd] == "v_b" + @test g[2th] == "v_b" + @test g[3rd] == "v_c" + @test g[3th] == "v_c" + @test g[1st => 2nd] === :e_ab + @test g[2nd => 1st] === :e_ab + @test g[2nd => 3rd] === :e_bc + @test g[3rd => 2nd] === :e_bc + end end