From a2b1e841c3d026c25598a696b31f4a2df451d48f Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 14:47:06 -0500 Subject: [PATCH 01/26] [PartitionedGraphs] Some `QuotientView` fixes and improvements - `vertices(::QuotientView)` now directly returns the keys `paritioned_vertices` return value. - `edges(::QuotientView)` now directly returns the edges of the `quotient_graph` return value (to coincide with interface overloading priority) - Converting a `QuotientView` to graph now calls `quotient_graph` directly - Adding methods for return directed/undirected graph types. Fix imports Fix rebase --- src/lib/PartitionedGraphs/src/quotientview.jl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/quotientview.jl b/src/lib/PartitionedGraphs/src/quotientview.jl index b8eb4e9..4096f60 100644 --- a/src/lib/PartitionedGraphs/src/quotientview.jl +++ b/src/lib/PartitionedGraphs/src/quotientview.jl @@ -1,5 +1,5 @@ using Graphs: AbstractGraph, rem_vertex!, rem_edge!, vertices, edges -using .GraphsExtensions: add_edges! +using .GraphsExtensions: directed_graph_type, undirected_graph_type using ..NamedGraphs: NamedGraph, position_graph_type struct QuotientView{V, G <: AbstractGraph} <: AbstractNamedGraph{V} @@ -11,21 +11,24 @@ Base.parent(qg::QuotientView) = qg.graph parent_graph_type(g::AbstractGraph) = parent_graph_type(typeof(g)) parent_graph_type(::Type{<:QuotientView{V, G}}) where {V, G} = G -function Base.copy(qv::QuotientView) - qg = quotient_graph_type(parent_graph_type(qv))(vertices(qv)) - add_edges!(qg, edges(qv)) - return qg -end +Base.copy(qv::QuotientView) = copy(quotient_graph(parent(qv))) NamedGraphs.edgetype(Q::Type{<:QuotientView}) = quotient_graph_edgetype(parent_graph_type(Q)) -Graphs.vertices(qg::QuotientView) = parent.(quotientvertices(parent(qg))) -Graphs.edges(qg::QuotientView) = parent.(quotientedges(parent(qg))) +Graphs.vertices(qg::QuotientView) = keys(partitioned_vertices(parent(qg))) +Graphs.edges(qg::QuotientView) = edges(quotient_graph(parent(qg))) function NamedGraphs.position_graph_type(type::Type{<:QuotientView}) return position_graph_type(quotient_graph_type(parent_graph_type(type))) end +function NamedGraphs.GraphsExtensions.directed_graph_type(type::Type{<:QuotientView}) + return directed_graph_type(quotient_graph_type(parent_graph_type(type))) +end +function NamedGraphs.GraphsExtensions.undirected_graph_type(type::Type{<:QuotientView}) + return undirected_graph_type(quotient_graph_type(parent_graph_type(type))) +end + function Graphs.rem_vertex!(qg::QuotientView, v) rem_quotientvertex!(parent(qg), QuotientVertex(v)) return qg From be7d2196127014480ccfea412eba43323044b98b Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 14:49:21 -0500 Subject: [PATCH 02/26] [PartitionedGraphs] Add directed/undirected graph type methos for `PartitionedGraph` --- src/lib/PartitionedGraphs/src/partitionedgraph.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib/PartitionedGraphs/src/partitionedgraph.jl b/src/lib/PartitionedGraphs/src/partitionedgraph.jl index 1ef0f55..e21635a 100644 --- a/src/lib/PartitionedGraphs/src/partitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/partitionedgraph.jl @@ -2,7 +2,7 @@ using Dictionaries: Dictionary using Graphs: AbstractEdge, AbstractGraph, add_edge!, edges, has_edge, induced_subgraph, vertices, dst, src, edgetype using ..NamedGraphs: NamedGraphs, NamedEdge, NamedGraph -using ..NamedGraphs.GraphsExtensions: GraphsExtensions, boundary_edges, is_self_loop, partition_vertices +using ..NamedGraphs.GraphsExtensions: GraphsExtensions, boundary_edges, is_self_loop, partition_vertices, directed_graph_type, undirected_graph_type using ..NamedGraphs.OrderedDictionaries: OrderedDictionary # TODO: Parametrize `partitioned_vertices` and `which_partition`, @@ -176,3 +176,11 @@ function NamedGraphs.induced_subgraph_from_vertices( sg, vs = NamedGraphs.induced_subgraph_from_vertices(pg, subvertices.vertices) return unpartitioned_graph(sg), vs end + + +function GraphsExtensions.directed_graph_type(type::Type{<:PartitionedGraph}) + return directed_graph_type(unpartitioned_graph_type(type)) +end +function GraphsExtensions.undirected_graph_type(type::Type{<:PartitionedGraph}) + return undirected_graph_type(unpartitioned_graph_type(type)) +end From e453d7f35770896212cf48215e09f66aa1f7fb91 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 16:16:05 -0500 Subject: [PATCH 03/26] [PartitionedGraphs] Add `similar_type` method for `QuotientView`. --- src/lib/PartitionedGraphs/src/quotientview.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/PartitionedGraphs/src/quotientview.jl b/src/lib/PartitionedGraphs/src/quotientview.jl index 4096f60..27ea732 100644 --- a/src/lib/PartitionedGraphs/src/quotientview.jl +++ b/src/lib/PartitionedGraphs/src/quotientview.jl @@ -1,6 +1,7 @@ using Graphs: AbstractGraph, rem_vertex!, rem_edge!, vertices, edges -using .GraphsExtensions: directed_graph_type, undirected_graph_type using ..NamedGraphs: NamedGraph, position_graph_type +using .GraphsExtensions: directed_graph_type, undirected_graph_type +using ..SimilarType: similar_type struct QuotientView{V, G <: AbstractGraph} <: AbstractNamedGraph{V} graph::G @@ -50,3 +51,7 @@ for f in [ end end end + +function NamedGraphs.SimilarType.similar_type(type::Type{<:QuotientView}) + return similar_type(quotient_graph_type(parent_graph_type(type))) +end From 9487b513dba5bc3e52c631ef1aa4403d8af7c349 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 16:18:37 -0500 Subject: [PATCH 04/26] [PartitionedGraphs] Add `quotientview` interface function This behaves similarly to `partitionedgraph` function. --- src/lib/PartitionedGraphs/src/quotientview.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/PartitionedGraphs/src/quotientview.jl b/src/lib/PartitionedGraphs/src/quotientview.jl index 27ea732..e62ebb9 100644 --- a/src/lib/PartitionedGraphs/src/quotientview.jl +++ b/src/lib/PartitionedGraphs/src/quotientview.jl @@ -55,3 +55,5 @@ end function NamedGraphs.SimilarType.similar_type(type::Type{<:QuotientView}) return similar_type(quotient_graph_type(parent_graph_type(type))) end + +quotientview(g::AbstractGraph) = QuotientView(g) From 6bfb9b44f0c4e2603d950fcf4f38540357c86760 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 16:32:27 -0500 Subject: [PATCH 05/26] [PartitionedGraphs] `quotient_graph` now returns a graph of similar type by default This function can now be used `SimpleGraph` etc without promoting to `NamedGraph`. --- src/lib/GraphsExtensions/src/abstractgraph.jl | 3 +++ .../src/abstractpartitionedgraph.jl | 22 +++++++++++++++++-- .../PartitionedGraphs/src/partitionedview.jl | 5 +++++ src/lib/PartitionedGraphs/src/quotientview.jl | 2 +- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/lib/GraphsExtensions/src/abstractgraph.jl b/src/lib/GraphsExtensions/src/abstractgraph.jl index fae210b..d2f7dc3 100644 --- a/src/lib/GraphsExtensions/src/abstractgraph.jl +++ b/src/lib/GraphsExtensions/src/abstractgraph.jl @@ -52,6 +52,9 @@ function convert_vertextype(V::Type, graph::AbstractGraph) return not_implemented() end +function graph_from_vertices(graph::AbstractGraph, vertices) + return graph_from_vertices(typeof(graph), vertices) +end function graph_from_vertices(graph_type::Type{<:AbstractGraph}, vertices) return graph_type(vertices) end diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index 9d1fa51..85e8e76 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -2,6 +2,7 @@ using Dictionaries: Dictionary using Graphs: AbstractEdge, AbstractGraph, + AbstractSimpleGraph, Graphs, add_vertex!, dst, @@ -13,16 +14,33 @@ using Graphs: vertices using ..NamedGraphs: NamedGraphs, AbstractNamedGraph, NamedGraph using ..NamedGraphs.GraphsExtensions: - GraphsExtensions, add_vertices!, not_implemented, rem_vertices!, subgraph, vertextype + GraphsExtensions, + add_vertices!, + graph_from_vertices, + not_implemented, + rem_vertices!, + similar_graph, + subgraph, + vertextype # For you own graph type `g`, you should define a method for this function if you # desire custom partitioning. partitioned_vertices(g::AbstractGraph) = [vertices(g)] +# This is not part of the interface. The interface function is +# `GraphExtensions.graph_from_vertices`, but for now just use a default for +# an `AbstractNamedGraph`. +function _quotient_graph_from_vertices(g::AbstractSimpleGraph, vertices) + return graph_from_vertices(g, vertices) +end +function _quotient_graph_from_vertices(::AbstractGraph, vertices) + return NamedGraph(vertices) +end + # For fast quotient edge checking and graph construction, one should overload this function. function quotient_graph(g::AbstractGraph) - qg = NamedGraph(keys(partitioned_vertices(g))) + qg = _quotient_graph_from_vertices(g, keys(partitioned_vertices(g))) for e in edges(g) qv_src = parent(quotientvertex(g, src(e))) diff --git a/src/lib/PartitionedGraphs/src/partitionedview.jl b/src/lib/PartitionedGraphs/src/partitionedview.jl index 422f585..34f670c 100644 --- a/src/lib/PartitionedGraphs/src/partitionedview.jl +++ b/src/lib/PartitionedGraphs/src/partitionedview.jl @@ -9,3 +9,8 @@ end unpartitioned_graph(pv::PartitionedView) = getfield(pv, :graph) partitioned_vertices(pv::PartitionedView) = getfield(pv, :partitioned_vertices) + +# So partitions of `AbstractSimpleGraph` make `AbstractSimpleGraph`s +function _quotient_graph_from_vertices(graph::PartitionedView, vertices) + return _quotient_graph_from_vertices(unpartitioned_graph(graph), vertices) +end diff --git a/src/lib/PartitionedGraphs/src/quotientview.jl b/src/lib/PartitionedGraphs/src/quotientview.jl index e62ebb9..22aab93 100644 --- a/src/lib/PartitionedGraphs/src/quotientview.jl +++ b/src/lib/PartitionedGraphs/src/quotientview.jl @@ -40,9 +40,9 @@ function Graphs.rem_edge!(qg::QuotientView, v) end for f in [ + :(NamedGraphs.vertex_positions), :(NamedGraphs.induced_subgraph_from_vertices), :(NamedGraphs.ordered_vertices), - :(NamedGraphs.vertex_positions), :(NamedGraphs.position_graph), ] @eval begin From a7d5a5830dd475d8a6b2d5009cee0687edf760e0 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 17:26:39 -0500 Subject: [PATCH 06/26] Version bump --- Project.toml | 2 +- examples/Project.toml | 2 +- test/Project.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 7def7bf..7cf3472 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "NamedGraphs" uuid = "678767b0-92e7-4007-89e4-4527a8725b19" authors = ["Matthew Fishman , Joseph Tindall and contributors"] -version = "0.8.2" +version = "0.8.3" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" diff --git a/examples/Project.toml b/examples/Project.toml index 7b23abb..3553a9f 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -4,4 +4,4 @@ NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" [compat] Graphs = "1.12.0" -NamedGraphs = "0.8.1" +NamedGraphs = "0.8.3" diff --git a/test/Project.toml b/test/Project.toml index bccfd82..025ec6c 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -24,7 +24,7 @@ Graphs = "1.12" GraphsFlows = "0.1.1" KaHyPar = "0.3.1" Metis = "1.5.0" -NamedGraphs = "0.8.1" +NamedGraphs = "0.8.3" SafeTestsets = "0.1.0" SimpleGraphAlgorithms = "0.6.0" SimpleGraphConverter = "0.1.0" From b6f1f6b545e43e249299cd31de00b7e25b335453 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 17:35:35 -0500 Subject: [PATCH 07/26] [PartitionGraphs] fallback method for `show` --- src/abstractnamedgraph.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index 6c40eb3..8612f05 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -45,6 +45,7 @@ abstract type AbstractNamedGraph{V} <: AbstractGraph{V} end Graphs.vertices(graph::AbstractNamedGraph) = not_implemented() position_graph(graph::AbstractNamedGraph) = not_implemented() +position_graph(graph::AbstractSimpleGraph) = graph Graphs.rem_vertex!(graph::AbstractNamedGraph, vertex) = not_implemented() Graphs.add_vertex!(graph::AbstractNamedGraph, vertex) = not_implemented() From 3702ef6098c0cf3773dceadc3557c0fcf634bdac Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Mon, 24 Nov 2025 18:12:46 -0500 Subject: [PATCH 08/26] Fix missing import --- src/abstractnamedgraph.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index 8612f05..c54a7d9 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -2,6 +2,7 @@ using Dictionaries: set! using Graphs: Graphs, AbstractGraph, + AbstractSimpleGraph, IsDirected, a_star, add_edge!, From 4dc46111a1790b2e2f69dfdaddead696accd1b62 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 25 Nov 2025 09:49:59 -0500 Subject: [PATCH 09/26] Remove broken import --- src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index 85e8e76..920abf0 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -19,7 +19,6 @@ using ..NamedGraphs.GraphsExtensions: graph_from_vertices, not_implemented, rem_vertices!, - similar_graph, subgraph, vertextype From f1641a203aafe8268534e723676690dae4284da1 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 25 Nov 2025 16:39:50 -0500 Subject: [PATCH 10/26] [PartitionedGraphs] Add `edgeless_quotient_graph` interface function. This function constructs a graph with no edges, but with vertices of the quotient graph. --- .../src/abstractpartitionedgraph.jl | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index 920abf0..3da030b 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -26,20 +26,13 @@ using ..NamedGraphs.GraphsExtensions: # desire custom partitioning. partitioned_vertices(g::AbstractGraph) = [vertices(g)] -# This is not part of the interface. The interface function is -# `GraphExtensions.graph_from_vertices`, but for now just use a default for -# an `AbstractNamedGraph`. -function _quotient_graph_from_vertices(g::AbstractSimpleGraph, vertices) - return graph_from_vertices(g, vertices) +function edgeless_quotient_graph(g::AbstractGraph) + return NamedGraph(keys(partitioned_vertices(g))) end -function _quotient_graph_from_vertices(::AbstractGraph, vertices) - return NamedGraph(vertices) -end - # For fast quotient edge checking and graph construction, one should overload this function. function quotient_graph(g::AbstractGraph) - qg = _quotient_graph_from_vertices(g, keys(partitioned_vertices(g))) + qg = edgeless_quotient_graph(g) for e in edges(g) qv_src = parent(quotientvertex(g, src(e))) From 36381cfcd90c922d2d4a8b77c7e39678fbebcba1 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 2 Dec 2025 19:19:17 -0500 Subject: [PATCH 11/26] [PartitionedGraphs] `quotient_graph` now returns a (un)directed graph depending on graph type. --- .../PartitionedGraphs/src/abstractpartitionedgraph.jl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index 3da030b..c641fbb 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -12,7 +12,7 @@ using Graphs: rem_vertex!, src, vertices -using ..NamedGraphs: NamedGraphs, AbstractNamedGraph, NamedGraph +using ..NamedGraphs: NamedGraphs, AbstractNamedGraph, NamedGraph, NamedDiGraph using ..NamedGraphs.GraphsExtensions: GraphsExtensions, add_vertices!, @@ -26,9 +26,15 @@ using ..NamedGraphs.GraphsExtensions: # desire custom partitioning. partitioned_vertices(g::AbstractGraph) = [vertices(g)] +#TODO: Write this in terms of traits function edgeless_quotient_graph(g::AbstractGraph) - return NamedGraph(keys(partitioned_vertices(g))) + if is_directed(g) + return NamedDiGraph(keys(partitioned_vertices(g))) + else + return NamedGraph(keys(partitioned_vertices(g))) + end end + # For fast quotient edge checking and graph construction, one should overload this function. function quotient_graph(g::AbstractGraph) From 703363aed74feb63a5162c658da87390df0e0fd4 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 2 Dec 2025 19:20:59 -0500 Subject: [PATCH 12/26] [PartitionedGraphs] Explictly construct edges of correct type when creating quotient graph --- src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index c641fbb..09757c1 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -43,7 +43,7 @@ function quotient_graph(g::AbstractGraph) for e in edges(g) qv_src = parent(quotientvertex(g, src(e))) qv_dst = parent(quotientvertex(g, dst(e))) - qe = qv_src => qv_dst + qe = edgetype(qg)(qv_src => qv_dst) if qv_src != qv_dst && !has_edge(qg, qe) add_edge!(qg, qe) end From d2774661f03c8e44fc806e8c57420a675f464dec Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 2 Dec 2025 19:24:26 -0500 Subject: [PATCH 13/26] [PartitionedGraphs] `PartitionedGraph` now takes the quotient graph type as a parameter Allows for more generic quotient graph types. --- src/lib/PartitionedGraphs/src/partitionedgraph.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/partitionedgraph.jl b/src/lib/PartitionedGraphs/src/partitionedgraph.jl index e21635a..db0fdc4 100644 --- a/src/lib/PartitionedGraphs/src/partitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/partitionedgraph.jl @@ -7,9 +7,11 @@ using ..NamedGraphs.OrderedDictionaries: OrderedDictionary # TODO: Parametrize `partitioned_vertices` and `which_partition`, # see https://github.com/mtfishman/NamedGraphs.jl/issues/63. -struct PartitionedGraph{V, PV, G <: AbstractGraph{V}, P <: Dictionary} <: AbstractPartitionedGraph{V, PV} +struct PartitionedGraph{ + V, PV, G <: AbstractGraph{V}, QG <: AbstractGraph{PV}, P <: Dictionary, + } <: AbstractPartitionedGraph{V, PV} graph::G - quotient_graph::NamedGraph{PV} + quotient_graph::QG partitioned_vertices::P which_partition::Dictionary{V, PV} end From e55cb9fcc5e862eea22b1fd39841b660537628c4 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 2 Dec 2025 19:25:58 -0500 Subject: [PATCH 14/26] Fix typo as `graph_type` -> `graph`. --- src/namedgraph.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/namedgraph.jl b/src/namedgraph.jl index 05d1a12..7ec16eb 100644 --- a/src/namedgraph.jl +++ b/src/namedgraph.jl @@ -171,10 +171,10 @@ end GenericNamedGraph() = GenericNamedGraph(Any[]) function GenericNamedGraph(graph::GenericNamedGraph) - return GenericNamedGraph{vertextype(graph), position_graph_type(graph_type)}(graph) + return GenericNamedGraph{vertextype(graph), position_graph_type(graph)}(graph) end function GenericNamedGraph{V}(graph::GenericNamedGraph) where {V} - return GenericNamedGraph{V, position_graph_type(graph_type)}(graph) + return GenericNamedGraph{V, position_graph_type(graph)}(graph) end function GenericNamedGraph{<:Any, G}( graph::GenericNamedGraph From fa2608cc5bf9098320c19f45f35b340f5161176b Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Wed, 3 Dec 2025 09:33:08 -0500 Subject: [PATCH 15/26] [PartitionedGraphs] Add directed/undireced graph constructor functions for `PartitionedGraph` --- .../PartitionedGraphs/src/partitionedgraph.jl | 24 +++++++++++++++---- .../PartitionedGraphs/src/partitionedview.jl | 4 ++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/partitionedgraph.jl b/src/lib/PartitionedGraphs/src/partitionedgraph.jl index db0fdc4..feefee4 100644 --- a/src/lib/PartitionedGraphs/src/partitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/partitionedgraph.jl @@ -180,9 +180,23 @@ function NamedGraphs.induced_subgraph_from_vertices( end -function GraphsExtensions.directed_graph_type(type::Type{<:PartitionedGraph}) - return directed_graph_type(unpartitioned_graph_type(type)) -end -function GraphsExtensions.undirected_graph_type(type::Type{<:PartitionedGraph}) - return undirected_graph_type(unpartitioned_graph_type(type)) +function GraphsExtensions.undirected_graph(g::PartitionedGraph) + dg = GraphsExtensions.undirected_graph(unpartitioned_graph(g)) + return PartitionedGraph(dg, partitioned_vertices(g)) +end +function GraphsExtensions.directed_graph(g::PartitionedGraph) + dg = GraphsExtensions.directed_graph(unpartitioned_graph(g)) + return PartitionedGraph(dg, partitioned_vertices(g)) +end +function GraphsExtensions.undirected_graph_type(type::Type{<:PartitionedGraph{V, PV}}) where {V, PV} + UG = undirected_graph_type(unpartitioned_graph_type(type)) + QG = undirected_graph_type(quotient_graph_type(type)) + P = fieldtype(type, :partitioned_vertices) + return PartitionedGraph{V, PV, UG, QG, P} +end +function GraphsExtensions.directed_graph_type(type::Type{<:PartitionedGraph{V, PV}}) where {V, PV} + DG = directed_graph_type(unpartitioned_graph_type(type)) + QG = directed_graph_type(quotient_graph_type(type)) + P = fieldtype(type, :partitioned_vertices) + return PartitionedGraph{V, PV, DG, QG, P} end diff --git a/src/lib/PartitionedGraphs/src/partitionedview.jl b/src/lib/PartitionedGraphs/src/partitionedview.jl index 34f670c..e78746f 100644 --- a/src/lib/PartitionedGraphs/src/partitionedview.jl +++ b/src/lib/PartitionedGraphs/src/partitionedview.jl @@ -10,6 +10,10 @@ end unpartitioned_graph(pv::PartitionedView) = getfield(pv, :graph) partitioned_vertices(pv::PartitionedView) = getfield(pv, :partitioned_vertices) +function unpartitioned_graph_type(graph_type::Type{<:PartitionedView}) + return fieldtype(graph_type, :graph) +end + # So partitions of `AbstractSimpleGraph` make `AbstractSimpleGraph`s function _quotient_graph_from_vertices(graph::PartitionedView, vertices) return _quotient_graph_from_vertices(unpartitioned_graph(graph), vertices) From e81da685ea934986e06937df919f6383595de5bc Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Wed, 3 Dec 2025 09:34:56 -0500 Subject: [PATCH 16/26] Remove redundant `directed_graph` method, add fallbacks `NamedGraph` methods for `AbstractSimpleGraph`. --- src/abstractnamedgraph.jl | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index c54a7d9..1ea70dd 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -35,7 +35,8 @@ using .GraphsExtensions: incident_edges, partition_vertices, rename_vertices, - subgraph + subgraph, + graph_from_vertices using SimpleTraits: SimpleTraits, Not, @traitfn abstract type AbstractNamedGraph{V} <: AbstractGraph{V} end @@ -63,10 +64,12 @@ end # graph `position_graph(graph::AbstractNamedGraph)`. # Inverse map of `ordered_vertices`. vertex_positions(graph::AbstractNamedGraph) = not_implemented() +vertex_positions(graph::AbstractSimpleGraph) = vertices(graph) # Outputs an object that when indexed by a vertex position # returns the corresponding vertex. ordered_vertices(graph::AbstractNamedGraph) = not_implemented() +ordered_vertices(graph::AbstractSimpleGraph) = vertices(graph) Graphs.edgetype(graph::AbstractNamedGraph) = edgetype(typeof(graph)) Graphs.edgetype(::Type{<:AbstractNamedGraph}) = not_implemented() @@ -114,16 +117,6 @@ Graphs.SimpleDiGraph(graph::AbstractNamedGraph) = SimpleDiGraph(position_graph(g Base.zero(G::Type{<:AbstractNamedGraph}) = G() -# TODO: Implement using `copyto!`? -function GraphsExtensions.directed_graph(graph::AbstractNamedGraph) - digraph = directed_graph_type(typeof(graph))(vertices(graph)) - for e in edges(graph) - add_edge!(digraph, e) - add_edge!(digraph, reverse(e)) - end - return digraph -end - # Default, can overload Base.eltype(graph::AbstractNamedGraph) = eltype(vertices(graph)) @@ -495,9 +488,7 @@ end # traversal algorithms. function Graphs.tree(graph::AbstractNamedGraph, parents) n = length(parents) - # TODO: Use `directed_graph` here to make more generic? - ## t = GenericNamedGraph(DiGraph(n), vertices(graph)) - t = directed_graph_type(typeof(graph))(vertices(graph)) + t = graph_from_vertices(directed_graph_type(typeof(graph)), vertices(graph)) for destination in eachindex(parents) source = parents[destination] if source != destination From d7fe1ee3b972e3bb6756076037dd267a0c2e6a9d Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Wed, 3 Dec 2025 11:26:08 -0500 Subject: [PATCH 17/26] [PartitionedGraphs] Remove overlapping method --- src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index 09757c1..fb41d20 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -133,12 +133,6 @@ function unpartitioned_graph_type(pg::AbstractPartitionedGraph) return typeof(unpartitioned_graph(pg)) end - -# AbstractGraph interface. -function Graphs.is_directed(graph_type::Type{<:AbstractPartitionedGraph}) - return is_directed(unpartitioned_graph_type(graph_type)) -end - #Functions for the abstract type Graphs.vertices(pg::AbstractPartitionedGraph) = vertices(unpartitioned_graph(pg)) Graphs.edges(pg::AbstractPartitionedGraph) = edges(unpartitioned_graph(pg)) From 809f5b81c5f008d87fd8956df1aa7793f892e7d7 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Wed, 3 Dec 2025 11:26:29 -0500 Subject: [PATCH 18/26] Add fall back for `position_graph_type` based on `promote_op`. --- src/abstractnamedgraph.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index 1ea70dd..dfe5fdb 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -107,6 +107,7 @@ end # position_graph_type(graph::AbstractNamedGraph) = typeof(position_graph(graph)) +position_graph_type(T::Type{<:AbstractNamedGraph}) = Base.promote_op(position_graph, T) function Graphs.has_vertex(graph::AbstractNamedGraph, vertex) # TODO: `vertices` should have fast lookup! From 02789ebc2447299c55f63917c10bab1f2cce886a Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Wed, 3 Dec 2025 11:26:58 -0500 Subject: [PATCH 19/26] Test structs now implemented the correct interface for `NamedGraphs` --- test/test_partitionedgraph.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_partitionedgraph.jl b/test/test_partitionedgraph.jl index 4a0fd07..3a57289 100644 --- a/test/test_partitionedgraph.jl +++ b/test/test_partitionedgraph.jl @@ -255,17 +255,23 @@ Graphs.vertices(mg::MyUnpartitionedGraph) = vertices(mg.g) Graphs.edgetype(mg::MyUnpartitionedGraph) = edgetype(mg.g) Graphs.has_edge(mg::MyUnpartitionedGraph, e) = has_edge(mg.g, e) +Graphs.is_directed(mg::MyUnpartitionedGraph) = is_directed(mg.g) + struct MyGraph{V, P} <: AbstractGraph{V} g::NamedGraph{V} partitioned_vertices::P end + Graphs.edges(mg::MyGraph) = edges(mg.g) Graphs.vertices(mg::MyGraph) = vertices(mg.g) Graphs.edgetype(mg::MyGraph) = edgetype(mg.g) Graphs.has_edge(mg::MyGraph, e) = has_edge(mg.g, e) +Graphs.is_directed(mg::MyGraph) = is_directed(mg.g) +NamedGraphs.position_graph(mg::MyGraph) = NamedGraphs.position_graph(mg.g) + PartitionedGraphs.partitioned_vertices(mg::MyGraph) = mg.partitioned_vertices PartitionedGraphs.quotient_graph_type(::Type{<:MyGraph}) = NamedGraph{Int} @@ -287,6 +293,9 @@ end Graphs.edges(wg::WrapperGraph) = edges(wg.g) Graphs.vertices(wg::WrapperGraph) = vertices(wg.g) +Graphs.is_directed(wg::WrapperGraph) = is_directed(wg.g) +NamedGraphs.position_graph(wg::WrapperGraph) = NamedGraphs.position_graph(wg.g) + PartitionedGraphs.partitioned_vertices(wg::WrapperGraph) = partitioned_vertices(wg.g) @testset "Partitioning of non-partitioned graphs" begin From 0ae1425c5ac370a535dc63514328e69f05542437 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Thu, 4 Dec 2025 11:19:10 -0500 Subject: [PATCH 20/26] Add `add_vertices!` method for `AbstractSimpleGraph`; - argument `vertices` must be of type `Base.OneTo{Int}`. --- src/lib/GraphsExtensions/src/simplegraph.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/GraphsExtensions/src/simplegraph.jl b/src/lib/GraphsExtensions/src/simplegraph.jl index 568ac14..7255a09 100644 --- a/src/lib/GraphsExtensions/src/simplegraph.jl +++ b/src/lib/GraphsExtensions/src/simplegraph.jl @@ -30,3 +30,10 @@ undirected_graph_type(G::Type{<:SimpleGraph}) = G # TODO: Use traits to make this more general. directed_graph_type(G::Type{<:SimpleDiGraph}) = G undirected_graph_type(G::Type{<:SimpleDiGraph}) = SimpleGraph{vertextype(G)} + +function add_vertices!(graph::AbstractSimpleGraph, vertices::Base.OneTo{Int}) + for _ in vertices + add_vertex!(graph) + end + return graph +end From e1627a9e05fda814f70f3dcd2fb765c23b6c7788 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Thu, 4 Dec 2025 11:26:50 -0500 Subject: [PATCH 21/26] Rename `graph_from_vertices` -> `similar_graph` and add single, double, and triple argument methods. This interface is to overload `similar_graph(graph)`, i.e. the single argument method. --- src/abstractnamedgraph.jl | 4 +-- src/lib/GraphsExtensions/src/abstractgraph.jl | 29 +++++++++++++++---- src/lib/GraphsExtensions/src/simplegraph.jl | 5 +--- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index dfe5fdb..753936f 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -36,7 +36,7 @@ using .GraphsExtensions: partition_vertices, rename_vertices, subgraph, - graph_from_vertices + similar_graph using SimpleTraits: SimpleTraits, Not, @traitfn abstract type AbstractNamedGraph{V} <: AbstractGraph{V} end @@ -489,7 +489,7 @@ end # traversal algorithms. function Graphs.tree(graph::AbstractNamedGraph, parents) n = length(parents) - t = graph_from_vertices(directed_graph_type(typeof(graph)), vertices(graph)) + t = similar_graph(directed_graph_type(typeof(graph)), vertices(graph)) for destination in eachindex(parents) source = parents[destination] if source != destination diff --git a/src/lib/GraphsExtensions/src/abstractgraph.jl b/src/lib/GraphsExtensions/src/abstractgraph.jl index d2f7dc3..42398e1 100644 --- a/src/lib/GraphsExtensions/src/abstractgraph.jl +++ b/src/lib/GraphsExtensions/src/abstractgraph.jl @@ -52,16 +52,33 @@ function convert_vertextype(V::Type, graph::AbstractGraph) return not_implemented() end -function graph_from_vertices(graph::AbstractGraph, vertices) - return graph_from_vertices(typeof(graph), vertices) +similar_graph(graph::AbstractGraph) = similar_graph(typeof(graph), vertices(graph)) +function similar_graph(T::Type{<:AbstractGraph}) + try + return T() + catch e + if e isa MethodError + return not_implemented() + else + rethrow(e) + end + end +end + +function similar_graph(graph, vertices) + new_graph = convert_vertextype(eltype(vertices), similar_graph(graph)) + add_vertices!(new_graph, vertices) + return new_graph end -function graph_from_vertices(graph_type::Type{<:AbstractGraph}, vertices) - return graph_type(vertices) +function similar_graph(graph, vertices, edges) + new_graph = similar_graph(graph, vertices) + add_edges!(new_graph, edges) + return new_graph end # TODO: Handle metadata in a generic way @traitfn function directed_graph(graph::::(!IsDirected)) - digraph = graph_from_vertices(directed_graph_type(graph), vertices(graph)) + digraph = similar_graph(directed_graph_type(graph), vertices(graph)) for e in edges(graph) add_edge!(digraph, e) add_edge!(digraph, reverse(e)) @@ -77,7 +94,7 @@ end # to avoid method overwrite warnings, see: # https://github.com/mauro3/SimpleTraits.jl#method-overwritten-warnings @traitfn function undirected_graph(graph::::IsDirected) - undigraph = graph_from_vertices(undirected_graph_type(typeof(graph)), vertices(graph)) + undigraph = similar_graph(undirected_graph_type(typeof(graph)), vertices(graph)) for e in edges(graph) # TODO: Check for repeated edges? add_edge!(undigraph, e) diff --git a/src/lib/GraphsExtensions/src/simplegraph.jl b/src/lib/GraphsExtensions/src/simplegraph.jl index 7255a09..8801be0 100644 --- a/src/lib/GraphsExtensions/src/simplegraph.jl +++ b/src/lib/GraphsExtensions/src/simplegraph.jl @@ -5,10 +5,7 @@ function permute_vertices(graph::AbstractSimpleGraph, permutation) end # https://github.com/JuliaGraphs/Graphs.jl/issues/365 -function graph_from_vertices(graph_type::Type{<:AbstractSimpleGraph}, vertices) - @assert vertices == Base.OneTo(length(vertices)) - return graph_type(length(vertices)) -end +similar_graph(graph_type::Type{<:AbstractSimpleGraph}) = graph_type() function convert_vertextype(vertextype::Type, graph::AbstractSimpleGraph) return not_implemented() From 19295060294562442db3bae0e7575f827fbeae16 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Thu, 4 Dec 2025 11:28:35 -0500 Subject: [PATCH 22/26] Rename `edgeless_quotient_graph` to `similar_quotient_graph`. This function now acts similarly to `similar_graph`. --- .../src/abstractpartitionedgraph.jl | 14 +++++++------ .../PartitionedGraphs/src/partitionedgraph.jl | 20 +++++++++++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index fb41d20..1a2c1b1 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -16,29 +16,31 @@ using ..NamedGraphs: NamedGraphs, AbstractNamedGraph, NamedGraph, NamedDiGraph using ..NamedGraphs.GraphsExtensions: GraphsExtensions, add_vertices!, - graph_from_vertices, not_implemented, rem_vertices!, subgraph, - vertextype + convert_vertextype # For you own graph type `g`, you should define a method for this function if you # desire custom partitioning. partitioned_vertices(g::AbstractGraph) = [vertices(g)] #TODO: Write this in terms of traits -function edgeless_quotient_graph(g::AbstractGraph) +function similar_quotient_graph(g::AbstractGraph) if is_directed(g) - return NamedDiGraph(keys(partitioned_vertices(g))) + sg = NamedDiGraph() else - return NamedGraph(keys(partitioned_vertices(g))) + sg = NamedGraph() end + return convert_vertextype(keytype(partitioned_vertices(g)), sg) end # For fast quotient edge checking and graph construction, one should overload this function. function quotient_graph(g::AbstractGraph) - qg = edgeless_quotient_graph(g) + qg = similar_quotient_graph(g) + + add_vertices!(qg, keys(partitioned_vertices(g))) for e in edges(g) qv_src = parent(quotientvertex(g, src(e))) diff --git a/src/lib/PartitionedGraphs/src/partitionedgraph.jl b/src/lib/PartitionedGraphs/src/partitionedgraph.jl index feefee4..2cd10ad 100644 --- a/src/lib/PartitionedGraphs/src/partitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/partitionedgraph.jl @@ -1,8 +1,24 @@ using Dictionaries: Dictionary using Graphs: - AbstractEdge, AbstractGraph, add_edge!, edges, has_edge, induced_subgraph, vertices, dst, src, edgetype + AbstractEdge, + AbstractGraph, + add_edge!, + edges, + has_edge, + induced_subgraph, + vertices, + dst, + src, + edgetype using ..NamedGraphs: NamedGraphs, NamedEdge, NamedGraph -using ..NamedGraphs.GraphsExtensions: GraphsExtensions, boundary_edges, is_self_loop, partition_vertices, directed_graph_type, undirected_graph_type +using ..NamedGraphs.GraphsExtensions: + GraphsExtensions, + boundary_edges, + is_self_loop, + partition_vertices, + directed_graph_type, + undirected_graph_type, + vertextype using ..NamedGraphs.OrderedDictionaries: OrderedDictionary # TODO: Parametrize `partitioned_vertices` and `which_partition`, From 3cd86a3f4254467e41d2e421a599e32b21186557 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Thu, 4 Dec 2025 11:51:51 -0500 Subject: [PATCH 23/26] Add tests for `similar_graph` function --- src/lib/GraphsExtensions/src/abstractgraph.jl | 2 +- src/lib/GraphsExtensions/test/runtests.jl | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/lib/GraphsExtensions/src/abstractgraph.jl b/src/lib/GraphsExtensions/src/abstractgraph.jl index 42398e1..7450d11 100644 --- a/src/lib/GraphsExtensions/src/abstractgraph.jl +++ b/src/lib/GraphsExtensions/src/abstractgraph.jl @@ -52,7 +52,7 @@ function convert_vertextype(V::Type, graph::AbstractGraph) return not_implemented() end -similar_graph(graph::AbstractGraph) = similar_graph(typeof(graph), vertices(graph)) +similar_graph(graph::AbstractGraph) = similar_graph(typeof(graph)) function similar_graph(T::Type{<:AbstractGraph}) try return T() diff --git a/src/lib/GraphsExtensions/test/runtests.jl b/src/lib/GraphsExtensions/test/runtests.jl index 3729ba5..7279b71 100644 --- a/src/lib/GraphsExtensions/test/runtests.jl +++ b/src/lib/GraphsExtensions/test/runtests.jl @@ -11,6 +11,7 @@ using AbstractTrees: rootindex using Dictionaries: Dictionary, Indices using Graphs: + AbstractGraph, add_edge!, add_vertex!, dst, @@ -44,6 +45,7 @@ using NamedGraphs.GraphsExtensions: add_edge, add_edges, add_edges!, + add_vertices!, all_edges, arrange_edge, arranged_edges, @@ -83,6 +85,7 @@ using NamedGraphs.GraphsExtensions: rem_edges!, rename_vertices, root_vertex, + similar_graph, subgraph, tree_graph_node, undirected_graph, @@ -108,6 +111,7 @@ using Test: @test, @test_broken, @test_throws, @testset # - random_bfs_tree @testset "NamedGraphs.GraphsExtensions" begin + # has_vertices g = path_graph(4) @test has_vertices(g, 1:3) @@ -552,6 +556,29 @@ using Test: @test, @test_broken, @test_throws, @testset @test_throws ErrorException root_vertex(g) @test_throws MethodError root_vertex(binary_tree(3)) + # similar_graph + g = path_graph(4) + @test similar_graph(g) isa typeof(g) + @test similar_graph(typeof(g)) isa typeof(g) + @test similar_graph(g, vertices(g), edges(g)) == g + @test !(similar_graph(g, vertices(g), edges(g)) === g) + sg = similar_graph(g, vertices(g)) + @test vertices(sg) == vertices(g) + @test isempty(edges(sg)) + + struct Graph <: AbstractGraph{Int} + field + end + + g = Graph(1) + @test_throws "Not implemented" similar_graph(g) + + # add_vertices! + g = path_graph(4) + add_vertices!(g, vertices(g)) + @test nv(g) == 8 + @test_throws MethodError add_vertices!(g, [2, 3]) + # add_edge g = SimpleGraph(4) add_edge!(g, 1 => 2) From 4ae23ee82102b44e93c4d50597b98bd8090478ca Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Thu, 4 Dec 2025 16:42:39 -0500 Subject: [PATCH 24/26] Add specific and fallback methods for `Base.reverse` with tests. --- src/abstractnamedgraph.jl | 13 +++++++++++-- src/namedgraph.jl | 8 ++++++++ test/test_namedgraph.jl | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index 753936f..8e55051 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -432,11 +432,20 @@ Graphs.is_connected(graph::AbstractNamedGraph) = is_connected(position_graph(gra Graphs.is_cyclic(graph::AbstractNamedGraph) = is_cyclic(position_graph(graph)) @traitfn function Base.reverse(graph::AbstractNamedGraph::IsDirected) - return not_implemented() + return similar_graph(graph, vertices, map(reverse, collect(edges(graph)))) end +# This wont be the most efficient way for a given graph type. @traitfn function Base.reverse!(g::AbstractNamedGraph::IsDirected) - return not_implemented() + + edge_list = edges(g) + + for edge in edge_list + rem_edge!(g, edge) + add_edge!(g, reverse(edge)) + end + + return g end # TODO: Move to `namedgraph.jl`, or make the output generic? diff --git a/src/namedgraph.jl b/src/namedgraph.jl index 7ec16eb..d83d108 100644 --- a/src/namedgraph.jl +++ b/src/namedgraph.jl @@ -240,6 +240,14 @@ function Graphs.induced_subgraph( return induced_subgraph_from_vertices(graph, to_vertices(graph, subvertices)) end +function Base.reverse!(graph::GenericNamedGraph) + reverse!(graph.position_graph) + return graph +end +function Base.reverse(graph::GenericNamedGraph) + return GenericNamedGraph(reverse(graph.position_graph), copy(graph.vertices)) +end + # # Type aliases # diff --git a/test/test_namedgraph.jl b/test/test_namedgraph.jl index 5e9f46b..9a63899 100644 --- a/test/test_namedgraph.jl +++ b/test/test_namedgraph.jl @@ -297,6 +297,24 @@ end h = degree_histogram(g, indegree) @test h[0] == 2 @test h[1] == 2 + + rg = reverse(g) + @warn edges(rg) + + @test !has_edge(rg, "A" => "B") + @test !has_edge(rg, "B" => "C") + @test has_edge(rg, "B" => "A") + @test has_edge(rg, "C" => "B") + + rg = reverse!(copy(g)) + + @test !has_edge(rg, "A" => "B") + @test !has_edge(rg, "B" => "C") + @test has_edge(rg, "B" => "A") + @test has_edge(rg, "C" => "B") + + @test reverse(reverse(g)) == g + @test reverse!(reverse!(copy(g))) == g end @testset "BFS traversal" begin g = named_grid((3, 3)) From d6d98fadc88bd050e617e3def551f66d30f016ef Mon Sep 17 00:00:00 2001 From: Jack Dunham <72548217+jack-dunham@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:53:41 -0500 Subject: [PATCH 25/26] Remove left over @warn statement in test file. Co-authored-by: Matt Fishman --- test/test_namedgraph.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_namedgraph.jl b/test/test_namedgraph.jl index 9a63899..93bcdfd 100644 --- a/test/test_namedgraph.jl +++ b/test/test_namedgraph.jl @@ -299,7 +299,6 @@ end @test h[1] == 2 rg = reverse(g) - @warn edges(rg) @test !has_edge(rg, "A" => "B") @test !has_edge(rg, "B" => "C") From 93a170791a7a5cb5cb0481700aaab19ed83d9036 Mon Sep 17 00:00:00 2001 From: Jack Dunham Date: Tue, 9 Dec 2025 12:22:16 -0500 Subject: [PATCH 26/26] Remove try/catch from `similar_graph`; remove auto conversion of `vertextype`; add explict `similar_graph` method for vertex conversion --- src/lib/GraphsExtensions/src/abstractgraph.jl | 19 +++++++------------ src/lib/GraphsExtensions/test/runtests.jl | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/lib/GraphsExtensions/src/abstractgraph.jl b/src/lib/GraphsExtensions/src/abstractgraph.jl index 7450d11..38a643c 100644 --- a/src/lib/GraphsExtensions/src/abstractgraph.jl +++ b/src/lib/GraphsExtensions/src/abstractgraph.jl @@ -53,20 +53,10 @@ function convert_vertextype(V::Type, graph::AbstractGraph) end similar_graph(graph::AbstractGraph) = similar_graph(typeof(graph)) -function similar_graph(T::Type{<:AbstractGraph}) - try - return T() - catch e - if e isa MethodError - return not_implemented() - else - rethrow(e) - end - end -end +similar_graph(T::Type{<:AbstractGraph}) = T() function similar_graph(graph, vertices) - new_graph = convert_vertextype(eltype(vertices), similar_graph(graph)) + new_graph = similar_graph(graph) add_vertices!(new_graph, vertices) return new_graph end @@ -76,6 +66,11 @@ function similar_graph(graph, vertices, edges) return new_graph end +function similar_graph(graph::AbstractGraph, vertex_type::Type) + new_graph = similar_graph(convert_vertextype(vertex_type, typeof(graph))) + return new_graph +end + # TODO: Handle metadata in a generic way @traitfn function directed_graph(graph::::(!IsDirected)) digraph = similar_graph(directed_graph_type(graph), vertices(graph)) diff --git a/src/lib/GraphsExtensions/test/runtests.jl b/src/lib/GraphsExtensions/test/runtests.jl index 7279b71..4a304f9 100644 --- a/src/lib/GraphsExtensions/test/runtests.jl +++ b/src/lib/GraphsExtensions/test/runtests.jl @@ -571,7 +571,7 @@ using Test: @test, @test_broken, @test_throws, @testset end g = Graph(1) - @test_throws "Not implemented" similar_graph(g) + @test_throws MethodError similar_graph(g) # add_vertices! g = path_graph(4)