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 8 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 KaHyPar
using Metis

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

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

@show length(vertices(pg_kahypar.partitioned_graph)) ==
length(vertices(pg_metis.partitioned_graph)) ==
npartitions
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved

@show typeof(pg_kahypar) <: PartitionedGraph
@show typeof(pg_metis) <: PartitionedGraph
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
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.
168 changes: 168 additions & 0 deletions src/Graphs/partitionedgraphs/abstractpartitionedgraph.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
abstract type AbstractPartitionedGraph{V,PV} <: AbstractNamedGraph{V} end

#Needed for interface
partitioned_graph(pg::AbstractPartitionedGraph) = not_implemented()
graph(pg::AbstractPartitionedGraph) = not_implemented()
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
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()
function edges(pg::AbstractPartitionedGraph, partition_edge::AbstractPartitionEdge)
return not_implemented()
end

vertices(pg::AbstractPartitionedGraph) = vertices(graph(pg))
parent_graph(pg::AbstractPartitionedGraph) = parent_graph(graph(pg))
function vertex_to_parent_vertex(pg::AbstractPartitionedGraph, vertex)
return vertex_to_parent_vertex(graph(pg), vertex)
end
edgetype(pg::AbstractPartitionedGraph) = edgetype(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
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
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!(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
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!(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_partition_edge!(pg_new, partition_edge)
return pg_new
end

function rem_partition_edges!(
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
pg::AbstractPartitionedGraph, partition_edges::Vector{AbstractPartitionEdge}
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
)
for pe in partition_edges
rem_edge!(pg, pe)
end
end

function rem_partition_edges(
pg::AbstractPartitionedGraph, partition_edges::Vector{AbstractPartitionEdge}
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
)
pg_new = copy(pg)
rem_partition_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!(graph(pg), vertex)
add_vertex!(partitioned_graph(pg), parent(partition_vertex))

return insert_to_vertex_map!(pg, vertex, partition_vertex)
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
end

function add_vertices!(
pg::AbstractPartitionedGraph,
vertices::Vector,
partition_vertices::Vector{V} where {V<:AbstractPartitionVertex},
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
)
@assert length(vertices) == length(partition_vertices)
for (v, pv) in zip(vertices, partition_vertices)
add_vertex!(pg, v, pv)
end
end

function add_vertices!(
pg::AbstractPartitionedGraph, vertices::Vector, partition_vertex::AbstractPartitionVertex
)
return add_vertices!(pg, vertices, fill(partition_vertex, length(vertices)))
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
end

function rem_vertex!(pg::AbstractPartitionedGraph, vertex)
rem_vertex!(graph(pg), vertex)
pv = which_partition(pg, vertex)
if length(vertices(pg, pv)) == 1
rem_vertex!(partitioned_graph(pg), parent(pv))
end
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
return delete_from_vertex_map!(pg, vertex)
end

function rem_vertex!(
pg::AbstractPartitionedGraph, partition_vertex::AbstractPartitionVertex
)
return rem_vertices!(pg, vertices(pg, partition_vertex))
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
end

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

function rem_vertices!(
pg::AbstractPartitionedGraph, partition_vertices::Vector{AbstractPartitionVertex}
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
)
for pv in partition_vertices
rem_vertex!(pg, pv)
end
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
end

function rem_vertices(
pg::AbstractPartitionedGraph, partition_vertices::Vector{AbstractPartitionVertex}
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
)
pg_new = copy(rem_partition_vertex)
rem_vertices!(pg_new, partition_vertices)
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 fieldnames(typeof(pg1)) != fieldnames(typeof(pg1))
return false
end

for field in fieldnames(typeof(pg1))
if getfield(pg1, field) != getfield(pg2, field)
return false
end
end
return true
end
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
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(p.first => p.second))
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
167 changes: 167 additions & 0 deletions src/Graphs/partitionedgraphs/partitionedgraph.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
struct PartitionedGraph{V,PV,G<:AbstractNamedGraph{V},PG<:AbstractNamedGraph{PV}} <:
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
AbstractPartitionedGraph{V,PV}
graph::G
partitioned_graph::PG
partitioned_vertices::Dictionary{PV,Vector{V}}
which_partition::Dictionary{V,PV}
end

##Constructors.
function PartitionedGraph{V,PV,G,PG}(
g::AbstractNamedGraph{V}, partitioned_vertices::Dictionary{PV,Vector{V}}
) where {V,PV,G<:AbstractNamedGraph{V},PG<:AbstractNamedGraph{PV}}
pvs = keys(partitioned_vertices)
pg = NamedGraph(pvs)
which_partition = Dictionary{V,PV}()
for v in vertices(g)
v_pvs = Set(findall(pv -> v ∈ partitioned_vertices[pv], pvs))
@assert length(v_pvs) == 1
insert!(which_partition, v, first(v_pvs))
end

for e in edges(g)
pv_src, pv_dst = which_partition[src(e)], which_partition[dst(e)]
pe = NamedEdge(pv_src => pv_dst)
if pv_src != pv_dst && !has_edge(pg, pe)
add_edge!(pg, pe)
end
end

return PartitionedGraph(g, pg, partitioned_vertices, which_partition)
end

function PartitionedGraph(
g::AbstractNamedGraph{V}, partitioned_vertices::Dictionary{PV,Vector{V}}
) where {V,PV}
return PartitionedGraph{V,PV,NamedGraph{V},NamedGraph{PV}}(g, partitioned_vertices)
end

function PartitionedGraph{V,Int64,G,NamedGraph{Int64}}(
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
g::AbstractNamedGraph{V}, partitioned_vertices::Vector{Vector{V}}
) where {V,G<:NamedGraph{V}}
partitioned_vertices_dict = Dictionary{Int64,Vector{V}}(
[i for i in 1:length(partitioned_vertices)], partitioned_vertices
)
return PartitionedGraph{V,Int64,NamedGraph{V},NamedGraph{Int64}}(
g, partitioned_vertices_dict
)
end

function PartitionedGraph(
g::AbstractNamedGraph{V}, partition_vertices::Vector{Vector{V}}
) where {V}
return PartitionedGraph{V,Int64,NamedGraph{V},NamedGraph{Int64}}(g, partition_vertices)
end

function PartitionedGraph{V,V,G,G}(vertices::Vector{V}) where {V,G<:NamedGraph{V}}
return PartitionedGraph(NamedGraph{V}(vertices), [[v] for v in vertices])
end

function PartitionedGraph(vertices::Vector{V}) where {V}
return PartitionedGraph{V,V,NamedGraph{V},NamedGraph{V}}(vertices)
end

function PartitionedGraph(
g::AbstractNamedGraph{V};
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
npartitions=nothing,
nvertices_per_partition=nothing,
backend=current_partitioning_backend(),
kwargs...,
) where {V}
partitioned_vertices = partition_vertices(
g; npartitions, nvertices_per_partition, backend, kwargs...
)
return PartitionedGraph(g, partitioned_vertices)
end

#Needed for interface
partitioned_graph(pg::PartitionedGraph) = getfield(pg, :partitioned_graph)
graph(pg::PartitionedGraph) = getfield(pg, :graph)
partitioned_vertices(pg::PartitionedGraph) = getfield(pg, :partitioned_vertices)
which_partition(pg::PartitionedGraph) = getfield(pg, :which_partition)
function vertices(pg::PartitionedGraph, partition_vert::PartitionVertex)
return partitioned_vertices(pg)[parent(partition_vert)]
end
function vertices(
pg::PartitionedGraph, partition_verts::Vector{V}
) where {V<:PartitionVertex}
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
return unique(reduce(vcat, [vertices(pg, pv) for pv in partition_verts]))
end
function which_partition(pg::PartitionedGraph, vertex)
return PartitionVertex(which_partition(pg)[vertex])
end

function partition_edge(pg::PartitionedGraph, edge::AbstractEdge)
return PartitionEdge(
parent(which_partition(pg, src(edge))) => parent(which_partition(pg, dst(edge)))
)
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)))
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
psrc_subgraph, pdst_subgraph, full_subgraph = subgraph(graph(pg), psrc_vs),
subgraph(pg, pdst_vs),
subgraph(pg, vcat(psrc_vs, pdst_vs))

return setdiff(
NamedGraphs.edges(full_subgraph),
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
vcat(NamedGraphs.edges(psrc_subgraph), NamedGraphs.edges(pdst_subgraph)),
)
end

#Copy on dictionaries is dodgy?!
function copy(pg::PartitionedGraph)
return PartitionedGraph(
copy(graph(pg)),
copy(partitioned_graph(pg)),
copy_keys_values(partitioned_vertices(pg)),
copy_keys_values(which_partition(pg)),
)
end

function insert_to_vertex_map!(
pg::PartitionedGraph, vertex, partition_vertex::PartitionVertex
)
pv = parent(partition_vertex)
if pv ∉ keys(partitioned_vertices(pg))
insert!(partitioned_vertices(pg), pv, [vertex])
else
pg.partitioned_vertices[pv] = unique(vcat(vertices(pg, partition_vertex), [vertex]))
end

return insert!(NamedGraphs.which_partition(pg), vertex, pv)
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
end

function delete_from_vertex_map!(pg::PartitionedGraph, vertex)
pv = which_partition(pg, vertex)
vs = vertices(pg, pv)
delete!(partitioned_vertices(pg), parent(pv))
if length(vs) != 1
insert!(partitioned_vertices(pg), parent(pv), setdiff(vs, [vertex]))
end
return delete!(pg.which_partition, vertex)
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
end

### PartitionedGraph Specific Functions
function induced_subgraph(pg::PartitionedGraph, vertices::Vector)
sub_pg_graph, _ = induced_subgraph(graph(pg), vertices)
sub_partitioned_vertices = copy_keys_values(partitioned_vertices(pg))
for pv in NamedGraphs.vertices(partitioned_graph(pg))
vs = intersect(vertices, sub_partitioned_vertices[pv])
if !isempty(vs)
sub_partitioned_vertices[pv] = vs
else
delete!(sub_partitioned_vertices, pv)
end
end

return PartitionedGraph(sub_pg_graph, sub_partitioned_vertices), nothing
end

### PartitionedGraph Specific Functions
function induced_subgraph(
pg::PartitionedGraph, partition_verts::Vector{V}
) where {V<:PartitionVertex}
return induced_subgraph(pg, vertices(pg, partition_verts))
end
JoeyT1994 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading