Skip to content

Commit

Permalink
Use GenericGraph for testing cycles algorithms (JuliaGraphs#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonschoelly authored Jul 5, 2023
1 parent 2760c27 commit ab2056a
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/cycles/basis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ julia> cycle_basis(g)
### References
* Paton, K. An algorithm for finding a fundamental set of cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518. [https://dl.acm.org/citation.cfm?id=363232]
"""
function cycle_basis(g::AbstractSimpleGraph, root=nothing)
function cycle_basis(g::AbstractGraph, root=nothing)
T = eltype(g)
cycles = Vector{Vector{T}}()

Expand Down
4 changes: 4 additions & 0 deletions src/cycles/johnson.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# TODO most functions here do not work for general abstract graphs yet
# as most of them relay on induced_subgraph, which expects the graph type
# to be modifiable.

abstract type Visitor{T<:Integer} end

"""
Expand Down
12 changes: 6 additions & 6 deletions test/cycles/basis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# No Edges
ex = Graph(1)
expected_cyclebasis = Array{Int64,1}[]
@testset "no edges" for g in testgraphs(ex)
@testset "no edges" for g in test_generic_graphs(ex)
ex_cyclebasis = @inferred cycle_basis(g)
@test isempty(ex_cyclebasis)
end
Expand All @@ -17,7 +17,7 @@
elist = [(1, 1)]
ex = Graph(SimpleEdge.(elist))
expected_cyclebasis = Array{Int64,1}[[1]]
@testset "one self-edge" for g in testgraphs(ex)
@testset "one self-edge" for g in test_generic_graphs(ex)
ex_cyclebasis = cycle_basis(g)
evaluate(ex_cyclebasis, expected_cyclebasis)
end
Expand All @@ -26,7 +26,7 @@
elist = [(1, 2), (2, 3), (3, 4), (4, 1), (1, 5)]
ex = Graph(SimpleEdge.(elist))
expected_cyclebasis = Array{Int64,1}[[1, 2, 3, 4]]
@testset "one cycle" for g in testgraphs(ex)
@testset "one cycle" for g in test_generic_graphs(ex)
ex_cyclebasis = cycle_basis(g)
evaluate(ex_cyclebasis, expected_cyclebasis)
end
Expand All @@ -35,7 +35,7 @@
elist = [(1, 2), (1, 3), (2, 3), (2, 4), (3, 4)]
ex = Graph(SimpleEdge.(elist))
expected_cyclebasis = Array{Int64,1}[[2, 3, 4], [2, 1, 3]]
@testset "2 of 3 cycles w/ basis" for g in testgraphs(ex)
@testset "2 of 3 cycles w/ basis" for g in test_generic_graphs(ex)
ex_cyclebasis = cycle_basis(g)
evaluate(ex_cyclebasis, expected_cyclebasis)
end
Expand All @@ -44,15 +44,15 @@
elist = [(1, 2), (1, 3), (2, 3), (2, 4), (3, 4), (1, 5), (5, 6), (6, 4)]
ex = Graph(SimpleEdge.(elist))
expected_cyclebasis = Array{Int64,1}[[2, 4, 3], [1, 5, 6, 4, 3], [1, 2, 3]]
@testset "root argument" for g in testgraphs(ex)
@testset "root argument" for g in test_generic_graphs(ex)
ex_cyclebasis = @inferred cycle_basis(g, 3)
evaluate(ex_cyclebasis, expected_cyclebasis)
end

@testset "two isolated cycles" begin
ex = blockdiag(cycle_graph(3), cycle_graph(4))
expected_cyclebasis = [[1, 2, 3], [4, 5, 6, 7]]
for g in testgraphs(ex)
for g in test_generic_graphs(ex)
found_cyclebasis = @inferred cycle_basis(g)
evaluate(expected_cyclebasis, found_cyclebasis)
end
Expand Down
13 changes: 7 additions & 6 deletions test/cycles/hawick-james.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@testset "subset" for g in testgraphs(ex1)
expected_circuits = Vector{Int}[[2, 3, 4, 5], [2, 3, 5]]
ex1_circuits = simplecycles_hawick_james(g)
ex1_circuits = simplecycles_hawick_james(GenericDiGraph(g))

@test issubset(expected_circuits, ex1_circuits)
@test issubset(ex1_circuits, expected_circuits)
Expand All @@ -20,22 +20,22 @@
add_edge!(g, 1, 1)
add_edge!(g, 3, 3)

ex1_circuits_self = simplecycles_hawick_james(g)
ex1_circuits_self = simplecycles_hawick_james(GenericDiGraph(g))

@test issubset(expected_circuits, ex1_circuits_self)
@test [1] ex1_circuits_self && [3] ex1_circuits_self
end

# Path DiGraph
ex2_size = 10
ex2 = testgraphs(path_digraph(ex2_size))
ex2 = test_generic_graphs(path_digraph(ex2_size))
@testset "empty" for g in ex2
@test isempty(simplecycles_hawick_james(g))
end

# Complete DiGraph
ex3_size = 5
ex3 = testgraphs(complete_digraph(ex3_size))
ex3 = test_generic_graphs(complete_digraph(ex3_size))
@testset "length" for g in ex3
ex3_circuits = simplecycles_hawick_james(g)
@test length(ex3_circuits) == length(unique(ex3_circuits))
Expand All @@ -62,7 +62,7 @@
add_edge!(ex4, src, dest)
add_edge!(ex4, dest, src)
end
@testset "membership" for g in testgraphs(ex4)
@testset "membership" for g in test_generic_graphs(ex4)
ex4_output = simplecycles_hawick_james(g)
@test [1, 2] ex4_output && [8, 9] ex4_output
end
Expand All @@ -72,8 +72,9 @@
(n, k) in [(14, 18), (10, 22), (7, 16)]

g = erdos_renyi(n, k; is_directed=true, rng=StableRNG(seed))
# TODO simplecycles(g) does not yet work with GenericDiGraph
cycles1 = simplecycles(g)
cycles2 = simplecycles_hawick_james(g)
cycles2 = simplecycles_hawick_james(GenericDiGraph(g))
foreach(sort!, cycles1)
foreach(sort!, cycles2)
sort!(cycles1)
Expand Down
4 changes: 4 additions & 0 deletions test/cycles/incremental.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# The test here cannot be done with GenericDiGraph, as the functions under test
# modify the graph. We probably need another generic graph type with more relaxed
# constraints for modifying graphs.

@testset "ICT" begin
Gempty = SimpleDiGraph(3)
Gsomedges = SimpleDiGraph(6)
Expand Down
3 changes: 3 additions & 0 deletions test/cycles/johnson.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# TODO we cannot run the test here with GenericGraph yet,
# as the functions don't work for arbitrary graphs yet.

@testset "Cycles" begin
rng = StableRNG(1)
completedg = complete_digraph(4)
Expand Down
6 changes: 3 additions & 3 deletions test/cycles/karp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
add_edge!(g1, 11, 7)
add_edge!(g1, 12, 9)

@testset "simple digraphs" for g in testgraphs(g1)
@testset "simple digraphs" for g in test_generic_graphs(g1)
c, λ = karp_minimum_cycle_mean(g, w)
@test c == [9, 11, 7]
@test λ == 0.9
Expand Down Expand Up @@ -78,7 +78,7 @@
1.0 Inf 0.0 Inf
]

@testset "tricky case" for g in testgraphs(tricky)
@testset "tricky case" for g in test_generic_graphs(tricky)
c, λ = karp_minimum_cycle_mean(g, distmx)
@test λ == 0.0
@test sort(c) == [3, 4]
Expand All @@ -97,7 +97,7 @@
Inf -1
]

@testset "multiple SCCs" for g in testgraphs(multi)
@testset "multiple SCCs" for g in test_generic_graphs(multi)
c, λ = karp_minimum_cycle_mean(g, distmx)
@test λ == -1.0
@test c == [2]
Expand Down
16 changes: 9 additions & 7 deletions test/cycles/limited_length.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pathdg = path_digraph(5)
cycledg = cycle_digraph(5)

@testset "complete digraph" for g in testgraphs(completedg)
@testset "complete digraph" for g in test_generic_graphs(completedg)
@test length(simplecycles_limited_length(g, 0)) == 0
@test length(simplecycles_limited_length(g, 1)) == 0
@test length(simplecycles_limited_length(g, 2)) == 6
Expand All @@ -13,15 +13,15 @@
@test length(simplecycles_limited_length(g, 4, typemax(Int))) == 20
end

@testset "path digraph" for g in testgraphs(pathdg)
@testset "path digraph" for g in test_generic_graphs(pathdg)
@test length(simplecycles_limited_length(g, 1)) == 0
@test length(simplecycles_limited_length(g, 2)) == 0
@test length(simplecycles_limited_length(g, 3)) == 0
@test length(simplecycles_limited_length(g, 4)) == 0
@test length(simplecycles_limited_length(g, 5)) == 0
end

@testset "cycle digraph" for g in testgraphs(cycledg)
@testset "cycle digraph" for g in test_generic_graphs(cycledg)
@test length(simplecycles_limited_length(g, 1)) == 0
@test length(simplecycles_limited_length(g, 2)) == 0
@test length(simplecycles_limited_length(g, 3)) == 0
Expand All @@ -30,12 +30,12 @@
end

@testset "self loops" begin
selfloopg = DiGraph([
selfloopg = GenericDiGraph(DiGraph([
0 1 0 0
0 0 1 0
1 0 1 0
0 0 0 1
])
]))
cycles = simplecycles_limited_length(selfloopg, nv(selfloopg))
@test [3] in cycles
@test [4] in cycles
Expand All @@ -46,10 +46,12 @@
@testset "octahedral graph" begin
octag = smallgraph(:octahedral)
octadg = DiGraph(octag)
# TODO simplecycleslength does currently not yet work with GenericDiGraph.
# This is probably because it uses induced_subgraph which fails on that graph type.
octalengths, _ = simplecycleslength(octadg)
for k in 1:6
@test sum(octalengths[1:k]) == length(simplecycles_limited_length(octag, k))
@test sum(octalengths[1:k]) == length(simplecycles_limited_length(octadg, k))
@test sum(octalengths[1:k]) == length(simplecycles_limited_length(GenericGraph(octag), k))
@test sum(octalengths[1:k]) == length(simplecycles_limited_length(GenericDiGraph(octadg), k))
end
end
end

0 comments on commit ab2056a

Please sign in to comment.