Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partitioned graphs #44

Merged
merged 32 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cf15123
New PartitionedGraph Interface and Type
JoeyT1994 Dec 8, 2023
4dfa7c0
Deeper PartitionedGraph Interface. Added KaHyPar and Metis Backending
JoeyT1994 Dec 11, 2023
a25e288
Utilised PartionVertex and PartitionEdge Types
JoeyT1994 Dec 12, 2023
04a5ef9
Formatting
JoeyT1994 Dec 13, 2023
e4d23ff
Cleaned up partitioning example
JoeyT1994 Dec 13, 2023
295ccd8
Added better vertex addition/removal options. Removed partitioning ex…
JoeyT1994 Dec 13, 2023
16a1834
Removed KaHyPar dependency from test
JoeyT1994 Dec 13, 2023
9d4a992
Better naming
JoeyT1994 Dec 14, 2023
a4b9589
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Dec 15, 2023
30ed16c
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Dec 15, 2023
ee15533
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Dec 15, 2023
92b3108
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Dec 15, 2023
a782cc3
Update src/Graphs/partitionedgraphs/partitionedgraph.jl
JoeyT1994 Dec 15, 2023
fd2fde2
Improved naming and interface
JoeyT1994 Dec 15, 2023
2c7d174
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Dec 18, 2023
e69ddb8
Improved equality of partitioned graph check
JoeyT1994 Dec 18, 2023
392e87f
Better testing
JoeyT1994 Dec 21, 2023
4548c98
Simplified constructor for PartitionedGraph, less type constraints
JoeyT1994 Dec 22, 2023
830667d
Better type based functions
JoeyT1994 Dec 23, 2023
3c996dd
Use function instead of field accessor
JoeyT1994 Dec 23, 2023
4d627cd
Removed implementation of directed(partitioned)graph). Better has_ver…
JoeyT1994 Jan 3, 2024
3a44997
Simplified has_vertex check for partitioned_graph
JoeyT1994 Jan 3, 2024
53ee51d
Formatting
JoeyT1994 Jan 8, 2024
bf82a6d
Defined rem/add_vertex as core function for abstractgraph interface
JoeyT1994 Jan 8, 2024
bef1b83
Better variable names and function structure
JoeyT1994 Jan 8, 2024
5010386
Added test dependencies
JoeyT1994 Jan 8, 2024
7f32e17
Only add KaHyPar dependency to example if not Windows
JoeyT1994 Jan 8, 2024
c0d2208
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Jan 9, 2024
134d39c
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Jan 9, 2024
30dfeb0
Update src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
JoeyT1994 Jan 9, 2024
acad1f1
Removed redundant function. Formatting
JoeyT1994 Jan 9, 2024
c893137
Cleanup. Avoid type piracy
JoeyT1994 Jan 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
GraphsFlows = "06909019-6f44-4949-96fc-b9d9aaa02889"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
SymRCM = "286e6d88-80af-4590-acc9-0001b223b9bd"

[compat]
Expand All @@ -24,6 +26,8 @@ SimpleTraits = "0.9"
SparseArrays = "1.7"
SplitApplyCombine = "1.2.2"
SymRCM = "0.2.1"
Suppressor = "0.2"
Requires = "1.3"
julia = "1.7"

[extras]
Expand Down
16 changes: 16 additions & 0 deletions examples/partitioning.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using NamedGraphs
using Metis

g = named_grid((4, 4))
npartitions = 4

pg_metis = PartitionedGraph(g; npartitions, backend="Metis")

@show pg_metis isa PartitionedGraph

if !Sys.iswindows()
using KaHyPar
pg_kahypar = PartitionedGraph(g; npartitions, backend="KaHyPar")
@show nv(partitioned_graph(pg_kahypar)) == nv(partitioned_graph(pg_metis)) == npartitions
@show pg_kahypar isa PartitionedGraph
end
27 changes: 24 additions & 3 deletions src/Graphs/abstractgraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -384,6 +384,29 @@ function mincut_partitions(graph::AbstractGraph, distmx=weights(graph))
return parts[1], parts[2]
end

function insert_vertex!(graph::AbstractGraph, vertex)
in_graph = !add_vertex!(graph, vertex)
if in_graph
error("Duplicate vertices are not allowed")
end
return graph
end

function delete_vertex!(graph::AbstractGraph, vertex)
in_graph = rem_vertex!(graph, vertex)
if !in_graph
error("Vertex not in graph")
end
return graph
end

function add_vertices!(graph::AbstractGraph, vs::Vector)
for vertex in vs
add_vertex!(graph, vertex)
end
return graph
end

"""Remove a list of edges from a graph g"""
function rem_edges!(g::AbstractGraph, edges)
for e in edges
Expand Down Expand Up @@ -450,7 +473,6 @@ function random_bfs_tree(g::AbstractGraph, s; maxiter=1000 * (nv(g) + ne(g)))
end
end
end

isempty_Q = isempty(Q)
if isempty_Q
break
Expand All @@ -459,6 +481,5 @@ function random_bfs_tree(g::AbstractGraph, s; maxiter=1000 * (nv(g) + ne(g)))
if !isempty_Q
error("Search failed to cover the graph in time. Consider increasing maxiter.")
end

return g_out
end
7 changes: 7 additions & 0 deletions src/Graphs/partitionedgraphs/abstractpartitionedge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
abstract type AbstractPartitionEdge{V} <: AbstractNamedEdge{V} end

parent(pe::AbstractPartitionEdge) = not_implemented()
src(pe::AbstractPartitionEdge) = not_implemented()
dst(pe::AbstractPartitionEdge) = not_implemented()

#Don't have the vertices wrapped. But wrap them with source and edge.
173 changes: 173 additions & 0 deletions src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
abstract type AbstractPartitionedGraph{V,PV} <: AbstractNamedGraph{V} end

#Needed for interface
partitioned_graph(pg::AbstractPartitionedGraph) = not_implemented()
unpartitioned_graph(pg::AbstractPartitionedGraph) = not_implemented()
which_partition(pg::AbstractPartitionedGraph, vertex) = not_implemented()
partitioned_vertices(pg::AbstractPartitionedGraph) = 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) = 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(PG::Type{<:AbstractPartitionedGraph}) = not_implemented()
directed_graph_type(PG::Type{<:AbstractPartitionedGraph}) = not_implemented()
undirected_graph_type(PG::Type{<:AbstractPartitionedGraph}) = not_implemented()

#Functions for the abstract type
vertices(pg::AbstractPartitionedGraph) = vertices(unpartitioned_graph(pg))
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))
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

function has_edge(pg::AbstractPartitionedGraph, edge::AbstractPartitionEdge)
return has_edge(partitioned_graph(pg), parent(partition_edge))
end

function is_boundary_edge(pg::AbstractPartitionedGraph, edge::AbstractEdge)
p_edge = partition_edge(pg, edge)
return src(p_edge) == dst(p_edge)
end

function add_edge!(pg::AbstractPartitionedGraph, edge::AbstractEdge)
add_edge!(unpartitioned_graph(pg), edge)
pg_edge = parent(partition_edge(pg, edge))
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)
pg_edge = partition_edge(pg, edge)
if has_edge(partitioned_graph(pg), pg_edge)
g_edges = edges(pg, pg_edge)
if length(g_edges) == 1
rem_edge!(partitioned_graph(pg), pg_edge)
end
end
return rem_edge!(unpartitioned_graph(pg), edge)
end

function rem_edge!(pg::AbstractPartitionedGraph, partition_edge::AbstractPartitionEdge)
return rem_edges!(pg, edges(pg, parent(partition_edge)))
end

function rem_edge(pg::AbstractPartitionedGraph, partition_edge::AbstractPartitionEdge)
pg_new = copy(pg)
rem_edge!(pg_new, partition_edge)
return pg_new
end

function rem_edges!(
pg::AbstractPartitionedGraph, partition_edges::Vector{<:AbstractPartitionEdge}
)
for pe in partition_edges
rem_edge!(pg, pe)
end
return pg
end

function rem_edges(
pg::AbstractPartitionedGraph, partition_edges::Vector{<:AbstractPartitionEdge}
)
pg_new = copy(pg)
rem_edges!(pg_new, partition_edges)
return pg_new
end

#Vertex addition and removal. I think it's important not to allow addition of a vertex without specification of PV
function add_vertex!(
pg::AbstractPartitionedGraph, vertex, partition_vertex::AbstractPartitionVertex
)
add_vertex!(unpartitioned_graph(pg), vertex)
add_vertex!(partitioned_graph(pg), parent(partition_vertex))
insert_to_vertex_map!(pg, vertex, partition_vertex)
return pg
end

function add_vertices!(
pg::AbstractPartitionedGraph,
vertices::Vector,
partition_vertices::Vector{<:AbstractPartitionVertex},
)
@assert length(vertices) == length(partition_vertices)
for (v, pv) in zip(vertices, partition_vertices)
add_vertex!(pg, v, pv)
end

return pg
end

function add_vertices!(
pg::AbstractPartitionedGraph, vertices::Vector, partition_vertex::AbstractPartitionVertex
)
add_vertices!(pg, vertices, fill(partition_vertex, length(vertices)))
return pg
end

function rem_vertex!(pg::AbstractPartitionedGraph, vertex)
pv = which_partition(pg, vertex)
delete_from_vertex_map!(pg, pv, vertex)
rem_vertex!(unpartitioned_graph(pg), vertex)
if !haskey(partitioned_vertices(pg), parent(pv))
rem_vertex!(partitioned_graph(pg), parent(pv))
end
return pg
end

function rem_vertex!(
pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex
)
rem_vertices!(pg, vertices(pg, partition_vertex))
return pg
end

function rem_vertex(pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex)
pg_new = copy(pg)
rem_vertex!(pg_new, partition_vertex)
return pg_new
end

function add_vertex!(pg::AbstractPartitionedGraph, vertex)
return error("Need to specify a partition where the new vertex will go.")
end

function (pg1::AbstractPartitionedGraph == pg2::AbstractPartitionedGraph)
if unpartitioned_graph(pg1) != unpartitioned_graph(pg2) ||
partitioned_graph(pg1) != partitioned_graph(pg2)
return false
end
for v in vertices(pg1)
if which_partition(pg1, v) != which_partition(pg2, v)
return false
end
end
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
4 changes: 4 additions & 0 deletions src/Graphs/partitionedgraphs/abstractpartitionvertex.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
abstract type AbstractPartitionVertex{V} <: Any where {V} end

#Parent, wrap, unwrap, vertex?
parent(pv::AbstractPartitionVertex) = not_implemented()
8 changes: 8 additions & 0 deletions src/Graphs/partitionedgraphs/partitionedge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
struct PartitionEdge{V,E<:AbstractEdge{V}} <: AbstractPartitionEdge{V}
edge::E
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(first(p) => last(p)))
Loading
Loading