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

Tests for various files with generic graph #278

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 13 additions & 3 deletions src/Test/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Test

using Graphs

export GenericEdge, GenericGraph, GenericDiGraph
export GenericEdge, GenericGraph, GenericDiGraph, generic_graph

"""
GenericEdge <: Graphs.AbstractEdge
Expand Down Expand Up @@ -37,7 +37,7 @@ struct GenericGraph{T} <: Graphs.AbstractGraph{T}
end

function GenericGraph(elist::Vector{Graphs.SimpleGraphEdge{T}}) where {T<:Integer}
GenericGraph{T}(SimpleGraph(elist))
return GenericGraph{T}(SimpleGraph(elist))
end

"""
Expand All @@ -50,8 +50,18 @@ struct GenericDiGraph{T} <: Graphs.AbstractGraph{T}
g::SimpleDiGraph{T}
end

"""
generic_graph(g::Union{SimpleGraph, SimpleDiGraph})

Return either a GenericGraph or GenericDiGraph that wraps a copy of g.
"""
function generic_graph(g::Union{SimpleGraph,SimpleDiGraph})
g = copy(g)
return is_directed(g) ? GenericDiGraph(g) : GenericGraph(g)
end

function GenericDiGraph(elist::Vector{Graphs.SimpleDiGraphEdge{T}}) where {T<:Integer}
GenericDiGraph{T}(SimpleDiGraph(elist))
return GenericDiGraph{T}(SimpleDiGraph(elist))
end

Graphs.is_directed(::Type{<:GenericGraph}) = false
Expand Down
4 changes: 4 additions & 0 deletions src/degeneracy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ Int64[]
```
"""
function k_corona(g::AbstractGraph, k; corenum=core_number(g))

# TODO k_corona does not correctly work for all AbstractGraph as
# it relies on induced_subgraph, which does not work on any AbstractGraph

kcore = k_core(g, k)
kcoreg = g[kcore]
kcoredeg = degree(kcoreg)
Expand Down
22 changes: 8 additions & 14 deletions src/operators.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# TODO most of the operators here do not work with any AbstractGraph yet
# as they require cloning and modifying graphs.

"""
complement(g)

Expand Down Expand Up @@ -402,25 +405,16 @@ end
# """Provides multiplication of a graph `g` by a vector `v` such that spectral
# graph functions in [GraphMatrices.jl](https://github.com/jpfairbanks/GraphMatrices.jl) can utilize Graphs natively.
# """
function *(g::Graph, v::Vector{T}) where {T<:Real}
length(v) == nv(g) || throw(ArgumentError("Vector size must equal number of vertices"))
y = zeros(T, nv(g))
for e in edges(g)
i = src(e)
j = dst(e)
y[i] += v[j]
y[j] += v[i]
end
return y
end

function *(g::DiGraph, v::Vector{T}) where {T<:Real}
function *(g::AbstractGraph, v::Vector{T}) where {T<:Real}
length(v) == nv(g) || throw(ArgumentError("Vector size must equal number of vertices"))
y = zeros(T, nv(g))
for e in edges(g)
i = src(e)
j = dst(e)
y[i] += v[j]
if !is_directed(g)
y[j] += v[i]
end
end
return y
end
Expand Down Expand Up @@ -481,7 +475,7 @@ julia> size(g, 3)
1
```
"""
size(g::Graph, dim::Int) = (dim == 1 || dim == 2) ? nv(g) : 1
size(g::AbstractGraph, dim::Int) = (dim == 1 || dim == 2) ? nv(g) : 1

"""
sum(g)
Expand Down
6 changes: 5 additions & 1 deletion src/traversals/bfs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ function _bfs_parents(g::AbstractGraph{T}, source, neighborfn::Function) where {
end
while !isempty(cur_level)
@inbounds for v in cur_level
@inbounds @simd for i in neighborfn(g, v)
# TODO we previously used @simd on the loop below, but this would fail
# if the result of neighorfn(g, v) would not implement firstindex
# If @simd really has a performance advantage, then maybe we make
# two different cases here.
@inbounds for i in neighborfn(g, v)
if !visited[i]
push!(next_level, i)
parents[i] = v
Expand Down
70 changes: 44 additions & 26 deletions test/connectivity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
add_edge!(gx, 8, 9)
add_edge!(gx, 10, 9)

for g in testgraphs(gx)
for g in test_generic_graphs(gx)
@test @inferred(!is_connected(g))
cc = @inferred(connected_components(g))
label = zeros(eltype(g), nv(g))
Expand All @@ -20,18 +20,18 @@
@test cclab[8] == [8, 9, 10]
@test length(cc) >= 3 && sort(cc[3]) == [8, 9, 10]
end
for g in testgraphs(g6)
for g in test_generic_graphs(g6)
@test @inferred(is_connected(g))
end

g10 = SimpleDiGraph(4)
add_edge!(g10, 1, 3)
add_edge!(g10, 2, 4)
for g in testdigraphs(g10)
for g in test_generic_graphs(g10)
@test @inferred(is_bipartite(g))
end
add_edge!(g10, 1, 4)
for g in testdigraphs(g10)
for g in test_generic_graphs(g10)
@test @inferred(is_bipartite(g))
end

Expand All @@ -45,7 +45,7 @@
end
if !has_edge(g, i, j)
add_edge!(g, i, j)
@test @inferred(is_bipartite(g))
@test @inferred(is_bipartite(GenericDiGraph(g)))
end
end
end
Expand All @@ -66,7 +66,7 @@
add_edge!(h, 7, 6)
add_edge!(h, 8, 4)
add_edge!(h, 8, 7)
for g in testdigraphs(h)
for g in test_generic_graphs(h)
@test @inferred(is_weakly_connected(g))
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
Expand All @@ -77,15 +77,27 @@
@test length(wcc) == 1 && length(wcc[1]) == nv(g)
end

function scc_ok(graph)
function scc_ok(graph::GenericDiGraph)
# Check that all SCC really are strongly connected

# TODO it might be better if we did not have to unwrap the GenericDiGraph
# (and we somehow might prevent this in the future) but currently the methods
# used in this utility test function do not work with GenericDiGraph yet.
graph = graph.g

scc = @inferred(strongly_connected_components(graph))
scc_as_subgraphs = map(i -> graph[i], scc)
return all(is_strongly_connected, scc_as_subgraphs)
end

function scc_k_ok(graph)
function scc_k_ok(graph::GenericDiGraph)
# Check that all SCC really are strongly connected

# TODO it might be better if we did not have to unwrap the GenericDiGraph
# (and we somehow might prevent this in the future) but currently the methods
# used in this utility test function do not work with GenericDiGraph yet.
graph = graph.g

scc_k = @inferred(strongly_connected_components_kosaraju(graph))
scc_k_as_subgraphs = map(i -> graph[i], scc_k)
return all(is_strongly_connected, scc_k_as_subgraphs)
Expand All @@ -97,7 +109,7 @@
add_edge!(h, 4, 2)
add_edge!(h, 2, 3)
add_edge!(h, 1, 3)
for g in testdigraphs(h)
for g in test_generic_graphs(h)
@test scc_ok(g)
@test scc_k_ok(g)
end
Expand All @@ -107,14 +119,14 @@
add_edge!(h2, 2, 4)
add_edge!(h2, 4, 3)
add_edge!(h2, 1, 3)
for g in testdigraphs(h2)
for g in test_generic_graphs(h2)
@test scc_ok(g)
@test scc_k_ok(g)
end

# Test case for empty graph
h = SimpleDiGraph(0)
for g in testdigraphs(h)
for g in test_generic_graphs(h)
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
@test length(scc) == 0
Expand All @@ -123,7 +135,7 @@

# Test case for graph with one vertex
h = SimpleDiGraph(1)
for g in testdigraphs(h)
for g in test_generic_graphs(h)
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
@test length(scc) == 1 && scc[1] == [1]
Expand All @@ -139,7 +151,7 @@
add_edge!(h, 2, 3)
add_edge!(h, 2, 1)

for g in testdigraphs(h)
for g in test_generic_graphs(h)
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
@test length(scc) == 2
Expand All @@ -159,7 +171,7 @@
add_edge!(h, 3, 5)
add_edge!(h, 5, 6)
add_edge!(h, 6, 4)
for g in testdigraphs(h)
for g in test_generic_graphs(h)
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
@test length(scc) == 1 && sort(scc[1]) == [1:6;]
Expand All @@ -171,7 +183,7 @@
add_edge!(h, 2, 3)
add_edge!(h, 3, 1)
add_edge!(h, 4, 1)
for g in testdigraphs(h)
for g in test_generic_graphs(h)
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
@test length(scc) == 2 && sort(scc[1]) == [1:3;] && sort(scc[2]) == [4]
Expand Down Expand Up @@ -200,7 +212,7 @@
add_edge!(h, 11, 12)
add_edge!(h, 12, 10)

for g in testdigraphs(h)
for g in test_generic_graphs(h)
scc = @inferred(strongly_connected_components(g))
scc_k = @inferred(strongly_connected_components_kosaraju(g))
@test length(scc) == 4
Expand All @@ -224,44 +236,50 @@
fig1[[3, 4, 9, 10, 11, 13, 18, 19, 22, 24]] = [
0.5, 0.4, 0.1, 1.0, 1.0, 0.2, 0.3, 0.2, 1.0, 0.3
]
fig1 = SimpleDiGraph(fig1)
fig1 = GenericDiGraph(SimpleDiGraph(fig1))
scc_fig1 = Vector[[2, 5], [1, 3, 4]]

# figure 2 example
fig2 = spzeros(5, 5)
fig2[[3, 10, 11, 13, 14, 17, 18, 19, 22]] .= 1
fig2 = SimpleDiGraph(fig2)
fig2 = GenericDiGraph(SimpleDiGraph(fig2))

# figure 3 example
fig3 = spzeros(8, 8)
fig3[[
1, 7, 9, 13, 14, 15, 18, 20, 23, 27, 28, 31, 33, 34, 37, 45, 46, 49, 57, 63, 64
]] .= 1
fig3 = SimpleDiGraph(fig3)
fig3 = GenericDiGraph(SimpleDiGraph(fig3))
scc_fig3 = Vector[[3, 4], [2, 5, 6], [8], [1, 7]]
fig3_cond = SimpleDiGraph(4)
add_edge!(fig3_cond, 4, 3)
add_edge!(fig3_cond, 2, 1)
add_edge!(fig3_cond, 4, 1)
add_edge!(fig3_cond, 4, 2)
fig3_cond

# construct a n-number edge ring graph (period = n)
n = 10
n_ring = cycle_digraph(n)
n_ring_shortcut = copy(n_ring)
add_edge!(n_ring_shortcut, 1, 4)
n_ring = GenericDiGraph(n_ring)
n_ring_shortcut = GenericDiGraph(n_ring_shortcut)

# figure 8 example
fig8 = spzeros(6, 6)
fig8[[2, 10, 13, 21, 24, 27, 35]] .= 1
fig8 = SimpleDiGraph(fig8)
fig8 = GenericDiGraph(SimpleDiGraph(fig8))

@test Set(@inferred(strongly_connected_components(fig1))) == Set(scc_fig1)
@test Set(@inferred(strongly_connected_components(fig3))) == Set(scc_fig3)

@test @inferred(period(n_ring)) == n
@test @inferred(period(n_ring_shortcut)) == 2

# TODO condensation currently returns a SimpleDiGraph, even if the input graph
# is a GenericDiGraph, so we compare with a SimpleDiGraph in this test,
# but one should think, if the condensation should not also be a GenericDiGraph
@test @inferred(condensation(fig3)) == fig3_cond

@test @inferred(attracting_components(fig1)) == Vector[[2, 5]]
Expand All @@ -270,7 +288,7 @@
g10dists = ones(10, 10)
g10dists[1, 2] = 10.0
g10 = star_graph(10)
for g in testgraphs(g10)
for g in test_generic_graphs(g10)
@test @inferred(neighborhood_dists(g, 1, 0)) == [(1, 0)]
@test length(@inferred(neighborhood(g, 1, 1))) == 10
@test length(@inferred(neighborhood(g, 1, 1, g10dists))) == 9
Expand All @@ -280,8 +298,8 @@
@test length(@inferred(neighborhood(g, 2, -1))) == 0
end
g10 = star_digraph(10)
for g in testdigraphs(g10)
@test @inferred(neighborhood_dists(g10, 1, 0, dir=:out)) == [(1, 0)]
for g in test_generic_graphs(g10)
@test @inferred(neighborhood_dists(g, 1, 0, dir=:out)) == [(1, 0)]
@test length(@inferred(neighborhood(g, 1, 1, dir=:out))) == 10
@test length(@inferred(neighborhood(g, 1, 1, g10dists, dir=:out))) == 9
@test length(@inferred(neighborhood(g, 2, 1, dir=:out))) == 1
Expand All @@ -301,7 +319,7 @@
##@test !@inferred(isgraphical([2]))

# Test simple digraphicality
sdg = SimpleDiGraph(10, 90)
sdg = GenericDiGraph(SimpleDiGraph(10, 90))
@test @inferred(isdigraphical(indegree(sdg), outdegree(sdg)))
@test !@inferred(isdigraphical([1, 1, 1], [1, 1, 0]))
@test @inferred(isdigraphical(Integer[], Integer[]))
Expand All @@ -314,14 +332,14 @@

# 1116
gc = cycle_graph(4)
for g in testgraphs(gc)
for g in test_generic_graphs(gc)
z = @inferred(neighborhood(g, 3, 3))
@test (z == [3, 2, 4, 1] || z == [3, 4, 2, 1])
end

gd = SimpleDiGraph([0 1 1 0; 0 0 0 1; 0 0 0 1; 0 0 0 0])
add_edge!(gd, 1, 4)
for g in testdigraphs(gd)
for g in test_generic_graphs(gd)
z = @inferred(neighborhood_dists(g, 1, 4))
@test (4, 1) ∈ z
@test (4, 2) ∉ z
Expand Down
Loading
Loading