Skip to content

Commit

Permalink
fix merge_vertices (#369)
Browse files Browse the repository at this point in the history
* fix merge_vertices

* fix tests

* Apply formatter

---------

Co-authored-by: Guillaume Dalle <[email protected]>
  • Loading branch information
etiennedeg and gdalle authored May 4, 2024
1 parent 94b84be commit 0445886
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 76 deletions.
50 changes: 25 additions & 25 deletions src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# as they require cloning and modifying graphs.

"""
complement(g)
complement(g)
Return the [graph complement](https://en.wikipedia.org/wiki/Complement_graph)
of a graph
Expand Down Expand Up @@ -58,7 +58,7 @@ function complement(g::DiGraph)
end

"""
reverse(g)
reverse(g)
Return a directed graph where all edges are reversed from the
original directed graph.
Expand Down Expand Up @@ -93,7 +93,7 @@ function reverse end
end

"""
reverse!(g)
reverse!(g)
In-place reverse of a directed graph (modifies the original graph).
See [`reverse`](@ref) for a non-modifying version.
Expand All @@ -105,7 +105,7 @@ function reverse! end
end

"""
blockdiag(g, h)
blockdiag(g, h)
Return a graph with ``|V(g)| + |V(h)|`` vertices and ``|E(g)| + |E(h)|``
edges where the vertices and edges from graph `h` are appended to graph `g`.
Expand Down Expand Up @@ -150,7 +150,7 @@ function blockdiag(g::T, h::T) where {T<:AbstractGraph}
end

"""
intersect(g, h)
intersect(g, h)
Return a graph with edges that are only in both graph `g` and graph `h`.
Expand Down Expand Up @@ -184,7 +184,7 @@ function intersect(g::T, h::T) where {T<:AbstractGraph}
end

"""
difference(g, h)
difference(g, h)
Return a graph with edges in graph `g` that are not in graph `h`.
Expand Down Expand Up @@ -218,7 +218,7 @@ function difference(g::T, h::T) where {T<:AbstractGraph}
end

"""
symmetric_difference(g, h)
symmetric_difference(g, h)
Return a graph with edges from graph `g` that do not exist in graph `h`,
and vice versa.
Expand Down Expand Up @@ -264,7 +264,7 @@ function symmetric_difference(g::T, h::T) where {T<:AbstractGraph}
end

"""
union(g, h)
union(g, h)
Return a graph that combines graphs `g` and `h` by taking the set union
of all vertices and edges.
Expand Down Expand Up @@ -319,7 +319,7 @@ function union(g::T, h::T) where {T<:AbstractSimpleGraph}
end

"""
join(g, h)
join(g, h)
Return a graph that combines graphs `g` and `h` using `blockdiag` and then
adds all the edges between the vertices in `g` and those in `h`.
Expand Down Expand Up @@ -359,7 +359,7 @@ function join(g::T, h::T) where {T<:AbstractGraph}
end

"""
crosspath(len::Integer, g::Graph)
crosspath(len::Integer, g::Graph)
Return a graph that duplicates `g` `len` times and connects each vertex
with its copies in a path.
Expand Down Expand Up @@ -420,7 +420,7 @@ function *(g::AbstractGraph, v::Vector{T}) where {T<:Real}
end

"""
sum(g, i)
sum(g, i)
Return a vector of indegree (`i`=1) or outdegree (`i`=2) values for graph `g`.
Expand Down Expand Up @@ -455,7 +455,7 @@ end

size(g::AbstractGraph) = (nv(g), nv(g))
"""
size(g, i)
size(g, i)
Return the number of vertices in `g` if `i`=1 or `i`=2, or `1` otherwise.
Expand All @@ -478,7 +478,7 @@ julia> size(g, 3)
size(g::AbstractGraph, dim::Int) = (dim == 1 || dim == 2) ? nv(g) : 1

"""
sum(g)
sum(g)
Return the number of edges in `g`.
Expand All @@ -495,7 +495,7 @@ julia> sum(g)
sum(g::AbstractGraph) = ne(g)

"""
sparse(g)
sparse(g)
Return the default adjacency matrix of `g`.
"""
Expand All @@ -518,7 +518,7 @@ end
end

"""
cartesian_product(g, h)
cartesian_product(g, h)
Return the [cartesian product](https://en.wikipedia.org/wiki/Cartesian_product_of_graphs)
of `g` and `h`.
Expand Down Expand Up @@ -570,7 +570,7 @@ function cartesian_product(g::G, h::G) where {G<:AbstractGraph}
end

"""
tensor_product(g, h)
tensor_product(g, h)
Return the [tensor product](https://en.wikipedia.org/wiki/Tensor_product_of_graphs)
of `g` and `h`.
Expand Down Expand Up @@ -618,8 +618,8 @@ end
## subgraphs ###

"""
induced_subgraph(g, vlist)
induced_subgraph(g, elist)
induced_subgraph(g, vlist)
induced_subgraph(g, elist)
Return the subgraph of `g` induced by the vertices in `vlist` or edges in `elist`
along with a vector mapping the new vertices to the old ones
Expand Down Expand Up @@ -706,15 +706,15 @@ function induced_subgraph(
end

"""
g[iter]
g[iter]
Return the subgraph induced by `iter`.
Equivalent to [`induced_subgraph`](@ref)`(g, iter)[1]`.
"""
getindex(g::AbstractGraph, iter) = induced_subgraph(g, iter)[1]

"""
egonet(g, v, d, distmx=weights(g))
egonet(g, v, d, distmx=weights(g))
Return the subgraph of `g` induced by the neighbors of `v` up to distance
`d`, using weights (optionally) provided by `distmx`.
Expand All @@ -735,7 +735,7 @@ function egonet(
end

"""
compute_shifts(n::Int, x::AbstractArray)
compute_shifts(n::Int, x::AbstractArray)
Determine how many elements of `x` are less than `i` for all `i` in `1:n`.
"""
Expand All @@ -746,7 +746,7 @@ function compute_shifts(n::Integer, x::AbstractArray)
end

"""
merge_vertices(g::AbstractGraph, vs)
merge_vertices(g::AbstractGraph, vs)
Create a new graph where all vertices in `vs` have been aliased to the same vertex `minimum(vs)`.
Expand All @@ -772,7 +772,7 @@ julia> collect(edges(h))
Edge 3 => 4
```
"""
function merge_vertices(g::AbstractSimpleGraph, vs)
function merge_vertices(g::G, vs) where {G<:AbstractSimpleGraph}
# Use lowest value as new vertex id.
vs = unique!(sort(vs))
merged_vertex = popfirst!(vs)
Expand All @@ -788,7 +788,7 @@ function merge_vertices(g::AbstractSimpleGraph, vs)
new_vertex_ids[vs] .= merged_vertex

# if v in vs then labels[v] == v0 else labels[v] == v
newg = SimpleGraph(nvnew)
newg = G(nvnew)
for e in edges(g)
u, w = src(e), dst(e)
if new_vertex_ids[u] != new_vertex_ids[w] # not a new self loop
Expand All @@ -799,7 +799,7 @@ function merge_vertices(g::AbstractSimpleGraph, vs)
end

"""
merge_vertices!(g, vs)
merge_vertices!(g, vs)
Combine vertices specified in `vs` into single vertex whose
index will be the lowest value in `vs`. All edges connected to vertices in `vs`
Expand Down
115 changes: 64 additions & 51 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,66 +56,79 @@

@testset "merge vertices" begin
# Check merge_vertices function.
h = Graph{T}(7)
add_edge!(h, 2, 5)
add_edge!(h, 3, 6)
add_edge!(h, 1, 7)
add_edge!(h, 6, 5)

h1 = Graph{T}(7)
add_edge!(h1, 2, 5)
add_edge!(h1, 3, 6)
add_edge!(h1, 1, 7)
add_edge!(h1, 6, 5)
vs = [2, 3, 7, 3, 3, 2]
hmerged = merge_vertices(h, vs)
hmerged = @inferred merge_vertices(h1, vs)
@test neighbors(hmerged, 1) == [2]
@test neighbors(hmerged, 2) == [1, 4, 5]
@test neighbors(hmerged, 3) == []
@test neighbors(hmerged, 4) == [2, 5]
@test eltype(hmerged) == eltype(g)

new_map = @inferred(merge_vertices!(h, vs))
new_map = @inferred(merge_vertices!(h1, vs))
@test new_map == [1, 2, 2, 3, 4, 5, 2]
@test neighbors(h, 1) == [2]
@test neighbors(h, 2) == [1, 4, 5]
@test neighbors(h, 3) == []
@test neighbors(hmerged, 4) == [2, 5]
@test hmerged == h

h = Graph{T}(7)
add_edge!(h, 1, 2)
add_edge!(h, 2, 3)
add_edge!(h, 2, 4)
add_edge!(h, 3, 4)
add_edge!(h, 3, 7)
new_map = @inferred(merge_vertices!(h, [2, 3, 2, 2]))
@test neighbors(h1, 1) == [2]
@test neighbors(h1, 2) == [1, 4, 5]
@test neighbors(h1, 3) == []
@test neighbors(h1, 4) == [2, 5]
@test hmerged == h1

h2 = path_digraph(4)
h2 = DiGraph{T}(h2)
hmerged = @inferred merge_vertices(h2, [2, 3])
@test is_directed(hmerged)
@test inneighbors(hmerged, 1) == []
@test inneighbors(hmerged, 2) == [1]
@test inneighbors(hmerged, 3) == [2]
@test outneighbors(hmerged, 1) == [2]
@test outneighbors(hmerged, 2) == [3]
@test outneighbors(hmerged, 3) == []
@test eltype(hmerged) == eltype(h2)

h3 = Graph{T}(7)
add_edge!(h3, 1, 2)
add_edge!(h3, 2, 3)
add_edge!(h3, 2, 4)
add_edge!(h3, 3, 4)
add_edge!(h3, 3, 7)
new_map = @inferred(merge_vertices!(h3, [2, 3, 2, 2]))
@test new_map == [1, 2, 2, 3, 4, 5, 6]
@test neighbors(h, 2) == [1, 3, 6]
@test neighbors(h, 1) == [2]
@test neighbors(h, 3) == [2]
@test neighbors(h, 4) == Int[]
@test neighbors(h, 6) == [2]
@test ne(h) == 3
@test nv(h) == 6

h2 = Graph{T}(7)
add_edge!(h2, 1, 2)
add_edge!(h2, 2, 3)
add_edge!(h2, 2, 4)
add_edge!(h2, 3, 4)
add_edge!(h2, 3, 7)
add_edge!(h2, 6, 7)
new_map = @inferred(merge_vertices!(h2, [2, 7, 3, 2]))
@test neighbors(h3, 2) == [1, 3, 6]
@test neighbors(h3, 1) == [2]
@test neighbors(h3, 3) == [2]
@test neighbors(h3, 4) == Int[]
@test neighbors(h3, 6) == [2]
@test ne(h3) == 3
@test nv(h3) == 6

h4 = Graph{T}(7)
add_edge!(h4, 1, 2)
add_edge!(h4, 2, 3)
add_edge!(h4, 2, 4)
add_edge!(h4, 3, 4)
add_edge!(h4, 3, 7)
add_edge!(h4, 6, 7)
new_map = @inferred(merge_vertices!(h4, [2, 7, 3, 2]))
@test new_map == [1, 2, 2, 3, 4, 5, 2]
@test neighbors(h2, 2) == [1, 3, 5]
@test neighbors(h2, 1) == [2]
@test neighbors(h2, 3) == [2]
@test neighbors(h2, 4) == Int[]
@test neighbors(h2, 5) == [2]
@test ne(h2) == 3
@test nv(h2) == 5

h3 = star_graph(5)
h3merged = merge_vertices(h3, [1, 2])
@test neighbors(h3merged, 1) == [2, 3, 4]
@test neighbors(h3merged, 2) == [1]
@test neighbors(h3merged, 3) == [1]
@test neighbors(h3merged, 4) == [1]
@test neighbors(h4, 2) == [1, 3, 5]
@test neighbors(h4, 1) == [2]
@test neighbors(h4, 3) == [2]
@test neighbors(h4, 4) == Int[]
@test neighbors(h4, 5) == [2]
@test ne(h4) == 3
@test nv(h4) == 5

h5 = star_graph(5)
h5 = Graph{T}(h5)
h5merged = merge_vertices(h5, [1, 2])
@test neighbors(h5merged, 1) == [2, 3, 4]
@test neighbors(h5merged, 2) == [1]
@test neighbors(h5merged, 3) == [1]
@test neighbors(h5merged, 4) == [1]
end
end

Expand Down

0 comments on commit 0445886

Please sign in to comment.