From 830667dc8133fd884aa8ca6009b991d00a65244c Mon Sep 17 00:00:00 2001 From: Joey Date: Sat, 23 Dec 2023 09:05:08 +0000 Subject: [PATCH] Better type based functions --- examples/partitioning.jl | 4 +- src/Graphs/abstractgraph.jl | 2 +- .../abstractpartitionedgraph.jl | 53 +++++++++++----- src/Graphs/partitionedgraphs/partitionedge.jl | 2 +- .../partitionedgraphs/partitionedgraph.jl | 62 ++++++++++--------- src/NamedGraphs.jl | 1 + src/abstractnamedgraph.jl | 8 +-- src/namedgraph.jl | 4 +- test/test_partitionedgraph.jl | 13 +--- 9 files changed, 82 insertions(+), 67 deletions(-) diff --git a/examples/partitioning.jl b/examples/partitioning.jl index 14fd353..687913b 100644 --- a/examples/partitioning.jl +++ b/examples/partitioning.jl @@ -8,9 +8,7 @@ npartitions = 4 pg_kahypar = PartitionedGraph(g; npartitions, backend="KaHyPar") pg_metis = PartitionedGraph(g; npartitions, backend="Metis") -@show length(NamedGraphs.vertices(partitioned_graph(pg_kahypar))) == - length(NamedGraphs.vertices(partitioned_graph(pg_metis))) == - npartitions +@show nv(partitioned_graph(pg_kahypar)) == nv(partitioned_graph(pg_metis)) == npartitions @show pg_kahypar isa PartitionedGraph @show pg_metis isa PartitionedGraph diff --git a/src/Graphs/abstractgraph.jl b/src/Graphs/abstractgraph.jl index 06b4409..abd8e23 100644 --- a/src/Graphs/abstractgraph.jl +++ b/src/Graphs/abstractgraph.jl @@ -43,7 +43,7 @@ end # to avoid method overwrite warnings, see: # https://github.com/mauro3/SimpleTraits.jl#method-overwritten-warnings @traitfn function undirected_graph(graph::::IsDirected) - undigraph = undirected_graph(typeof(graph))(vertices(graph)) + undigraph = 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/Graphs/partitionedgraphs/abstractpartitionedgraph.jl b/src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl index 34ddc1c..a6a0738 100644 --- a/src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl +++ b/src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl @@ -3,34 +3,34 @@ abstract type AbstractPartitionedGraph{V,PV} <: AbstractNamedGraph{V} end #Needed for interface partitioned_graph(pg::AbstractPartitionedGraph) = not_implemented() unpartitioned_graph(pg::AbstractPartitionedGraph) = not_implemented() -function vertices(pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex) - return not_implemented() -end which_partition(pg::AbstractPartitionedGraph, vertex) = not_implemented() copy(pg::AbstractPartitionedGraph) = not_implemented() delete_from_vertex_map!(pg::AbstractPartitionedGraph, vertex) = not_implemented() insert_to_vertex_map!(pg::AbstractPartitionedGraph, vertex) = not_implemented() -partition_edge(pg::AbstractPartitionedGraph, edge::AbstractEdge) = not_implemented() +partition_edge(pg::AbstractPartitionedGraph, edge) = not_implemented() function edges(pg::AbstractPartitionedGraph, partition_edge::AbstractPartitionEdge) return not_implemented() end +vertices(pg::AbstractPartitionedGraph, pv::AbstractPartitionVertex) = not_implemented() +function vertices( + pg::AbstractPartitionedGraph, partition_verts::Vector{V} +) where {V<:AbstractPartitionVertex} + return not_implemented() +end +parent_graph_type(G::Type{<:AbstractPartitionedGraph}) = not_implemented() +directed_graph_type(G::Type{<:AbstractPartitionedGraph}) = not_implemented() +undirected_graph_type(G::Type{<:AbstractPartitionedGraph}) = not_implemented() +#Functions for the abstract type vertices(pg::AbstractPartitionedGraph) = vertices(unpartitioned_graph(pg)) -#edges(pg::AbstractPartitionedGraph) = edges(unpartitioned_graph(pg)) -#nv(pg::AbstractPartitionedGraph) = nv(unpartitioned_graph(pg)) -#outneighbors(pg::AbstractPartitionedGraph, vertex) = outneighbors(unpartitioned_graph(pg), vertex) parent_graph(pg::AbstractPartitionedGraph) = parent_graph(unpartitioned_graph(pg)) function vertex_to_parent_vertex(pg::AbstractPartitionedGraph, vertex) return vertex_to_parent_vertex(unpartitioned_graph(pg), vertex) end edgetype(pg::AbstractPartitionedGraph) = edgetype(unpartitioned_graph(pg)) -function parent_graph_type(G::Type{<:AbstractPartitionedGraph}) - return fieldtype(fieldtype(G, :graph), :parent_graph) -end -directed_graph(G::Type{<:AbstractPartitionedGraph}) = directed_graph(fieldtype(G, :graph)) -function undirected_graph(G::Type{<:AbstractPartitionedGraph}) - return unddirected_graph(fieldtype(G, :graph)) -end +parent_graph_type(pg::AbstractPartitionedGraph) = parent_graph_type(unpartitioned_graph(pg)) +nv(pg::AbstractPartitionedGraph, pv::AbstractPartitionVertex) = length(vertices(pg, pv)) + function has_vertex(pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex) return has_vertex(partitioned_graph(pg), parent(partition_vertex)) end @@ -49,6 +49,8 @@ function add_edge!(pg::AbstractPartitionedGraph, edge::AbstractEdge) if src(pg_edge) != dst(pg_edge) add_edge!(partitioned_graph(pg), pg_edge) end + + return pg end function rem_edge!(pg::AbstractPartitionedGraph, edge::AbstractEdge) @@ -79,6 +81,8 @@ function rem_edges!( for pe in partition_edges rem_edge!(pg, pe) end + + return pg end function rem_edges( @@ -108,6 +112,8 @@ function add_vertices!( for (v, pv) in zip(vertices, partition_vertices) add_vertex!(pg, v, pv) end + + return pg end function add_vertices!( @@ -117,12 +123,13 @@ function add_vertices!( end function rem_vertex!(pg::AbstractPartitionedGraph, vertex) - rem_vertex!(unpartitioned_graph(pg), vertex) pv = which_partition(pg, vertex) - if length(vertices(pg, pv)) == 1 + delete_from_vertex_map!(pg, pv, vertex) + rem_vertex!(unpartitioned_graph(pg), vertex) + if iszero(nv(pg, pv)) rem_vertex!(partitioned_graph(pg), parent(pv)) end - return delete_from_vertex_map!(pg, vertex) + return pg end function rem_vertex!( @@ -143,6 +150,8 @@ function rem_vertices!( for pv in partition_vertices rem_vertex!(pg, pv) end + + return pg end function rem_vertices( @@ -171,3 +180,13 @@ function (pg1::AbstractPartitionedGraph == pg2::AbstractPartitionedGraph) return true end + +function subgraph(pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex) + return first(induced_subgraph(unpartitioned_graph(pg), vertices(pg, [partition_vertex]))) +end + +function induced_subgraph( + pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex +) + return subgraph(pg, partition_vertex), nothing +end diff --git a/src/Graphs/partitionedgraphs/partitionedge.jl b/src/Graphs/partitionedgraphs/partitionedge.jl index 597641a..4607b9d 100644 --- a/src/Graphs/partitionedgraphs/partitionedge.jl +++ b/src/Graphs/partitionedgraphs/partitionedge.jl @@ -5,4 +5,4 @@ end parent(pe::PartitionEdge) = getfield(pe, :edge) src(pe::PartitionEdge) = PartitionVertex(src(parent(pe))) dst(pe::PartitionEdge) = PartitionVertex(dst(parent(pe))) -PartitionEdge(p::Pair) = PartitionEdge(NamedEdge(p.first => p.second)) +PartitionEdge(p::Pair) = PartitionEdge(NamedEdge(first(p) => last(p))) diff --git a/src/Graphs/partitionedgraphs/partitionedgraph.jl b/src/Graphs/partitionedgraphs/partitionedgraph.jl index 943fad7..33d06b7 100644 --- a/src/Graphs/partitionedgraphs/partitionedgraph.jl +++ b/src/Graphs/partitionedgraphs/partitionedgraph.jl @@ -42,12 +42,21 @@ partitioned_graph(pg::PartitionedGraph) = getfield(pg, :partitioned_graph) unpartitioned_graph(pg::PartitionedGraph) = getfield(pg, :graph) partitioned_vertices(pg::PartitionedGraph) = getfield(pg, :partitioned_vertices) which_partition(pg::PartitionedGraph) = getfield(pg, :which_partition) +parent_graph_type(PG::Type{<:PartitionedGraph}) = fieldtype(PG, :graph) +function directed_graph_type(PG::Type{<:PartitionedGraph}) + return directed_graph_type(fieldtype(PG, :graph)) +end +function undirected_graph_type(PG::Type{<:PartitionedGraph}) + return undirected_graph_type(fieldtype(PG, :graph)) +end function vertices(pg::PartitionedGraph, partition_vert::PartitionVertex) - return partitioned_vertices(pg)[parent(partition_vert)] + if haskey(partitioned_vertices(pg), parent(partition_vert)) + return partitioned_vertices(pg)[parent(partition_vert)] + else + return [] + end end -function vertices( - pg::PartitionedGraph, partition_verts::Vector{V} -) where {V<:PartitionVertex} +function vertices(pg::PartitionedGraph, partition_verts::Vector{<:PartitionVertex}) return unique(reduce(vcat, [vertices(pg, pv) for pv in partition_verts])) end function which_partition(pg::PartitionedGraph, vertex) @@ -61,19 +70,15 @@ function partition_edge(pg::PartitionedGraph, edge::AbstractEdge) end function partition_edges(pg::PartitionedGraph, partition_edge::PartitionEdge) - psrc_vs, pdst_vs = vertices(pg, PartitionVertex(src(partition_edge))), - vertices(pg, PartitionVertex(dst(partition_edge))) - psrc_subgraph, pdst_subgraph, full_subgraph = subgraph(unpartitioned_graph(pg), psrc_vs), - subgraph(pg, pdst_vs), - subgraph(pg, vcat(psrc_vs, pdst_vs)) - - return setdiff( - NamedGraphs.edges(full_subgraph), - vcat(NamedGraphs.edges(psrc_subgraph), NamedGraphs.edges(pdst_subgraph)), - ) + psrc_vs = vertices(pg, PartitionVertex(src(partition_edge))) + pdst_vs = vertices(pg, PartitionVertex(dst(partition_edge))) + psrc_subgraph = subgraph(unpartitioned_graph(pg), psrc_vs) + pdst_subgraph = subgraph(pg, pdst_vs) + full_subgraph = subgraph(pg, vcat(psrc_vs, pdst_vs)) + + return setdiff(edges(full_subgraph), vcat(edges(psrc_subgraph), edges(pdst_subgraph))) end -#Copy on dictionaries is dodgy?! function copy(pg::PartitionedGraph) return PartitionedGraph( copy(unpartitioned_graph(pg)), @@ -93,17 +98,26 @@ function insert_to_vertex_map!( pg.partitioned_vertices[pv] = unique(vcat(vertices(pg, partition_vertex), [vertex])) end - return insert!(NamedGraphs.which_partition(pg), vertex, pv) + insert!(which_partition(pg), vertex, pv) + return pg end function delete_from_vertex_map!(pg::PartitionedGraph, vertex) pv = which_partition(pg, vertex) - vs = vertices(pg, pv) - delete!(partitioned_vertices(pg), parent(pv)) + return delete_from_vertex_map!(pg, pv, vertex) +end + +function delete_from_vertex_map!( + pg::PartitionedGraph, partitioned_vertex::PartitionVertex, vertex +) + vs = vertices(pg, partitioned_vertex) + delete!(partitioned_vertices(pg), parent(partitioned_vertex)) if length(vs) != 1 - insert!(partitioned_vertices(pg), parent(pv), setdiff(vs, [vertex])) + insert!(partitioned_vertices(pg), parent(partitioned_vertex), setdiff(vs, [vertex])) end - return delete!(pg.which_partition, vertex) + + delete!(which_partition(pg), vertex) + return partitioned_vertex end ### PartitionedGraph Specific Functions @@ -127,11 +141,3 @@ function induced_subgraph( ) where {V<:PartitionVertex} return induced_subgraph(pg, vertices(pg, partition_verts)) end - -function subgraph(pg::PartitionedGraph, partition_vertex::PartitionVertex) - return first(induced_subgraph(unpartitioned_graph(pg), vertices(pg, [partition_vertex]))) -end - -function induced_subgraph(pg::PartitionedGraph, partition_vertex::PartitionVertex) - return subgraph(pg, partition_vertex), nothing -end diff --git a/src/NamedGraphs.jl b/src/NamedGraphs.jl index 5e9dfa2..e3f1e0a 100644 --- a/src/NamedGraphs.jl +++ b/src/NamedGraphs.jl @@ -179,6 +179,7 @@ export NamedGraph, neighborhood, neighborhood_dists, neighbors, + nv, partitioned_graph, path_digraph, path_graph, diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index d2b15eb..876f74d 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -36,8 +36,8 @@ end # TODO: rename `edge_type`? edgetype(graph::AbstractNamedGraph) = not_implemented() -directed_graph(G::Type{<:AbstractNamedGraph}) = not_implemented() -undirected_graph(G::Type{<:AbstractNamedGraph}) = not_implemented() +directed_graph_type(G::Type{<:AbstractNamedGraph}) = not_implemented() +undirected_graph_type(G::Type{<:AbstractNamedGraph}) = not_implemented() # In terms of `parent_graph_type` # is_directed(::Type{<:AbstractNamedGraph}) = not_implemented() @@ -61,7 +61,7 @@ zero(G::Type{<:AbstractNamedGraph}) = G() # TODO: Implement using `copyto!`? function directed_graph(graph::AbstractNamedGraph) - digraph = directed_graph(typeof(graph))(vertices(graph)) + digraph = directed_graph_type(typeof(graph))(vertices(graph)) for e in edges(graph) add_edge!(digraph, e) add_edge!(digraph, reverse(e)) @@ -530,7 +530,7 @@ function 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(typeof(graph))(vertices(graph)) + t = directed_graph_type(typeof(graph))(vertices(graph)) for destination in eachindex(parents) source = parents[destination] if source != destination diff --git a/src/namedgraph.jl b/src/namedgraph.jl index 14fed66..aaaf1fd 100644 --- a/src/namedgraph.jl +++ b/src/namedgraph.jl @@ -159,10 +159,10 @@ function set_vertices(graph::GenericNamedGraph, vertices) return GenericNamedGraph(parent_graph(graph), vertices) end -function directed_graph(G::Type{<:GenericNamedGraph}) +function directed_graph_type(G::Type{<:GenericNamedGraph}) return GenericNamedGraph{vertextype(G),directed_graph(parent_graph_type(G))} end -function undirected_graph(G::Type{<:GenericNamedGraph}) +function undirected_graph_type(G::Type{<:GenericNamedGraph}) return GenericNamedGraph{vertextype(G),undirected_graph(parent_graph_type(G))} end diff --git a/test/test_partitionedgraph.jl b/test/test_partitionedgraph.jl index 5488e36..a099373 100644 --- a/test/test_partitionedgraph.jl +++ b/test/test_partitionedgraph.jl @@ -1,16 +1,7 @@ using Test using NamedGraphs using NamedGraphs: - spanning_forest, - subvertices, - spanning_tree, - forest_cover, - rem_edge!, - PartitionEdge, - rem_edges!, - PartitionVertex, - parent, - _npartitions + spanning_forest, spanning_tree, forest_cover, PartitionEdge, PartitionVertex, parent using Dictionaries using Graphs @@ -120,7 +111,7 @@ end for f in functions for g in gs pg = PartitionedGraph(g, [vertices(g)]) - @test f(pg) == f(pg.graph) + @test f(pg) == f(unpartitioned_graph(pg)) @test nv(pg) == nv(g) @test nv(partitioned_graph(pg)) == 1 @test ne(pg) == ne(g)