Skip to content

Commit 4d8e451

Browse files
pgrepdsgdalle
andauthored
Create induced subgraph from edge list (#37)
In order to fix [#32](#32), I have added an implementation of the `induced_subgraph` function that creates an edge induced subgraph from a list of edges. --------- Co-authored-by: Guillaume Dalle <[email protected]>
1 parent c508a11 commit 4d8e451

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
1919
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
2020
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
2121
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
22+
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
2223
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2324

2425
[targets]
25-
test = ["Aqua", "Documenter", "Graphs", "JuliaFormatter", "LinearAlgebra", "Test"]
26+
test = ["Aqua", "Documenter", "Graphs", "JuliaFormatter", "LinearAlgebra", "SparseArrays", "Test"]

src/overrides.jl

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,50 @@ Compute the weighted subgraph induced by a list of vertices.
162162
Return a tuple containing the new graph and the list of vertices.
163163
"""
164164
function Graphs.induced_subgraph(
165-
g::T, vlist::AbstractVector{U}
166-
) where {T<:AbstractSimpleWeightedGraph,U<:Integer}
167-
E = eltype(g)
165+
g::G, vlist::AbstractVector{U}
166+
) where {G<:AbstractSimpleWeightedGraph,U<:Integer}
167+
T = eltype(g)
168168
allunique(vlist) || throw(ArgumentError("Vertices in subgraph list must be unique"))
169-
new_weights = g.weights[E.(vlist), E.(vlist)]
169+
new_weights = g.weights[T.(vlist), T.(vlist)]
170170
newg = zero(g)
171171
newg.weights = new_weights
172-
return newg, Vector{E}(vlist)
172+
return newg, Vector{T}(vlist)
173+
end
174+
175+
function Graphs.induced_subgraph(
176+
g::G, elist::AbstractVector{E}
177+
) where {G<:AbstractSimpleWeightedGraph} where {E<:AbstractEdge}
178+
allunique(elist) || throw(ArgumentError("Edges in subgraph list must be unique"))
179+
T, U = eltype(g), weighttype(g)
180+
vertex_set = Set{T}()
181+
for e in elist
182+
if has_edge(g, e)
183+
push!(vertex_set, src(e), dst(e))
184+
else
185+
@warn "Skipping the edge $(e), since it does not exist in the graph!"
186+
end
187+
end
188+
vertex_list = collect(vertex_set)
189+
sort!(vertex_list)
190+
index_map = Dict(vertex_list[i] => i for i in eachindex(vertex_list))
191+
n = length(vertex_list)
192+
new_weights = spzeros(weighttype(g), T, n, n)
193+
I, J, W = T[], T[], U[]
194+
for e in elist
195+
if has_edge(g, e)
196+
i, j = index_map[src(e)], index_map[dst(e)]
197+
w = get_weight(g, dst(e), src(e))
198+
push!(I, j) # storage is transposed!
199+
push!(J, i)
200+
push!(W, w)
201+
if !is_directed(g)
202+
push!(I, i)
203+
push!(J, j)
204+
push!(W, w)
205+
end
206+
end
207+
end
208+
new_weights = sparse(I, J, W)
209+
newg = G(new_weights)
210+
return newg, vertex_list
173211
end

test/simpleweightedgraph.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SimpleWeightedGraphs
2+
using SparseArrays
23

34
@testset verbose = true "SimpleWeightedGraphs" begin
45
@info("Ignore warnings relating to adding and removing vertices and edges")
@@ -351,4 +352,33 @@ using SimpleWeightedGraphs
351352
@test g[1, 3, Val{:weight}()] 0
352353
@test g[2, 3, Val{:weight}()] 0.5
353354
end
355+
356+
# this testset was implemented for https://github.com/JuliaGraphs/SimpleWeightedGraphs.jl/issues/32
357+
@testset "induced_subgraph should preserve weights for edge lists" begin
358+
g = SimpleWeightedGraph([0 2; 2 0])
359+
expected_graph_weights = sparse([0 2; 2 0])
360+
# vertex induced subgraph
361+
vertex_induced_subgraph_weights = weights(first(induced_subgraph(g, [1, 2])))
362+
@test vertex_induced_subgraph_weights == expected_graph_weights
363+
# edge induced subgraph
364+
edge_induced_subgraph_weights = weights(first(induced_subgraph(g, [Edge(1, 2)])))
365+
@test edge_induced_subgraph_weights == expected_graph_weights
366+
367+
# test edge induced graph with one edge removed
368+
# graph isomorphic to C_5
369+
g = SimpleWeightedGraph([0 2 0 0 2; 2 0 2 0 0; 0 2 0 2 0; 0 0 2 0 2; 2 0 0 2 0])
370+
expected_graph_weights = sparse(
371+
[0 2 0 0 0; 2 0 2 0 0; 0 2 0 2 0; 0 0 2 0 2; 0 0 0 2 0]
372+
)
373+
# create edge induced subgraph isomorphic to P_5. The edge (1, 5) is missing and test if weights are correct.
374+
edge_induced_subgraph_weights = weights(
375+
first(induced_subgraph(g, [Edge(1, 2), Edge(2, 3), Edge(3, 4), Edge(4, 5)]))
376+
)
377+
@test edge_induced_subgraph_weights == expected_graph_weights
378+
379+
# test edge induced subgraph which does not contain the whole vertex set, especially remove the first column (vertex 1)
380+
edge_induced_subgraph_weights = weights(first(induced_subgraph(g, [Edge(2, 3)])))
381+
expected_graph_weights = sparse([0 2; 2 0])
382+
@test edge_induced_subgraph_weights == expected_graph_weights
383+
end
354384
end

0 commit comments

Comments
 (0)