From 01896fe57daa728c24ed252431632668b89dfea0 Mon Sep 17 00:00:00 2001 From: stecrotti Date: Wed, 23 Nov 2022 13:53:17 +0100 Subject: [PATCH 1/7] add regular tree generator with test --- src/SimpleGraphs/SimpleGraphs.jl | 1 + src/SimpleGraphs/generators/staticgraphs.jl | 62 ++++++++++++++++++++ test/simplegraphs/generators/staticgraphs.jl | 60 +++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/src/SimpleGraphs/SimpleGraphs.jl b/src/SimpleGraphs/SimpleGraphs.jl index 1a75a24d9..c1e664682 100644 --- a/src/SimpleGraphs/SimpleGraphs.jl +++ b/src/SimpleGraphs/SimpleGraphs.jl @@ -91,6 +91,7 @@ export AbstractSimpleGraph, cycle_digraph, binary_tree, double_binary_tree, + regular_tree, roach_graph, clique_graph, barbell_graph, diff --git a/src/SimpleGraphs/generators/staticgraphs.jl b/src/SimpleGraphs/generators/staticgraphs.jl index 64e004877..8f37a2e91 100644 --- a/src/SimpleGraphs/generators/staticgraphs.jl +++ b/src/SimpleGraphs/generators/staticgraphs.jl @@ -536,6 +536,68 @@ function double_binary_tree(k::Integer) return g end +""" + regular_tree(k::Integer, z::integer) + +Create a [k-regular tree](https://en.wikipedia.org/wiki/Bethe_lattice) +of depth `k` and degree `z`. + +# Examples +```jldoctest +julia> binary_tree(4) +{15, 14} undirected simple Int64 graph + +julia> binary_tree(Int8(5)) +{31, 30} undirected simple Int8 graph +``` +""" +function regular_tree(k::T, z::T) where {T<:Integer} + k <= 0 && return SimpleGraph(0) + k == 1 && return SimpleGraph(1) + if Graphs.isbounded(k) && BigInt(z)^k - 1 > typemax(k) + throw(DomainError(k, "z^k - 1 not representable by type $T")) + end + + n = T((z^k - 1) / (z - 1)) + ne = Int(n - 1) + fadjlist = Vector{Vector{T}}(undef, n) + + @inbounds fadjlist[1] = convert.(T, 2:(z + 1)) + @inbounds for l in 2:(k - 1) + w = Int((z^(l - 1) - 1) / (z - 1)) + x = w + z^(l - 1) + @simd for i in 1:(z^(l - 1)) + j = w + i + fadjlist[j] = [ + ceil(T, (j - x) / z) + w + convert.(T, (x + (i - 1) * z + 1):(x + i * z)) + ] + end + end + l = k + w = Int((z^(l - 1) - 1) / (z - 1)) + x = w + z^(l - 1) + @inbounds @simd for j in (w + 1):x + fadjlist[j] = T[ceil(Int, (j - x) / z) + w] + end + return SimpleGraph(ne, fadjlist) + + # n = T(2^k - 1) + # ne = Int(n - 1) + # fadjlist = Vector{Vector{T}}(undef, n) + # @inbounds fadjlist[1] = T[2, 3] + # @inbounds for i in 1:(k - 2) + # @simd for j in (2^i):(2^(i + 1) - 1) + # fadjlist[j] = T[j ÷ 2, 2j, 2j + 1] + # end + # end + # i = k - 1 + # @inbounds @simd for j in (2^i):(2^(i + 1) - 1) + # fadjlist[j] = T[j ÷ 2] + # end + # return SimpleGraph(ne, fadjlist) +end + """ roach_graph(k) diff --git a/test/simplegraphs/generators/staticgraphs.jl b/test/simplegraphs/generators/staticgraphs.jl index 17107adce..93a86a962 100644 --- a/test/simplegraphs/generators/staticgraphs.jl +++ b/test/simplegraphs/generators/staticgraphs.jl @@ -411,6 +411,66 @@ @test isvalid_simplegraph(g) end + @testset "Regular Trees" begin + g = @inferred(regular_tree(3, 3)) + I = [ + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13 + ] + J = [ + 2, + 3, + 4, + 1, + 5, + 6, + 7, + 8, + 1, + 9, + 10, + 1, + 11, + 12, + 13, + 2, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 4 + ] + V = ones(Int, length(I)) + Adj = sparse(I, J, V) + @test Adj == sparse(g) + @test isvalid_simplegraph(g) + end + @testset "Roach Graphs" begin rg3 = @inferred(roach_graph(3)) # [3] From dac8f9a0496ca5680c54093870b881a14ef47120 Mon Sep 17 00:00:00 2001 From: stecrotti Date: Wed, 23 Nov 2022 14:15:38 +0100 Subject: [PATCH 2/7] docstring for regular trees, one more test --- src/SimpleGraphs/generators/staticgraphs.jl | 26 +++++--------------- test/simplegraphs/generators/staticgraphs.jl | 2 ++ 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/SimpleGraphs/generators/staticgraphs.jl b/src/SimpleGraphs/generators/staticgraphs.jl index 8f37a2e91..a9fc43ddc 100644 --- a/src/SimpleGraphs/generators/staticgraphs.jl +++ b/src/SimpleGraphs/generators/staticgraphs.jl @@ -539,16 +539,17 @@ end """ regular_tree(k::Integer, z::integer) -Create a [k-regular tree](https://en.wikipedia.org/wiki/Bethe_lattice) +Create a [k-regular tree](https://en.wikipedia.org/wiki/Bethe_lattice), +also known as Bethe Lattice or Cayley Tree, of depth `k` and degree `z`. # Examples ```jldoctest -julia> binary_tree(4) -{15, 14} undirected simple Int64 graph +julia> regular_tree(4, 3) +{40, 39} undirected simple Int64 graph -julia> binary_tree(Int8(5)) -{31, 30} undirected simple Int8 graph +julia> regular_tree(5, 2) == binary_tree(5) +true ``` """ function regular_tree(k::T, z::T) where {T<:Integer} @@ -581,21 +582,6 @@ function regular_tree(k::T, z::T) where {T<:Integer} fadjlist[j] = T[ceil(Int, (j - x) / z) + w] end return SimpleGraph(ne, fadjlist) - - # n = T(2^k - 1) - # ne = Int(n - 1) - # fadjlist = Vector{Vector{T}}(undef, n) - # @inbounds fadjlist[1] = T[2, 3] - # @inbounds for i in 1:(k - 2) - # @simd for j in (2^i):(2^(i + 1) - 1) - # fadjlist[j] = T[j ÷ 2, 2j, 2j + 1] - # end - # end - # i = k - 1 - # @inbounds @simd for j in (2^i):(2^(i + 1) - 1) - # fadjlist[j] = T[j ÷ 2] - # end - # return SimpleGraph(ne, fadjlist) end """ diff --git a/test/simplegraphs/generators/staticgraphs.jl b/test/simplegraphs/generators/staticgraphs.jl index 93a86a962..6cb9649ad 100644 --- a/test/simplegraphs/generators/staticgraphs.jl +++ b/test/simplegraphs/generators/staticgraphs.jl @@ -469,6 +469,8 @@ Adj = sparse(I, J, V) @test Adj == sparse(g) @test isvalid_simplegraph(g) + # test that setting z = 2 recovers a binary tree + @test all(regular_tree(k, 2) == binary_tree(k) for k in 0:10) end @testset "Roach Graphs" begin From 7abb310b80e38829a25f1a1f048c85553de095ac Mon Sep 17 00:00:00 2001 From: stecrotti Date: Wed, 23 Nov 2022 14:19:59 +0100 Subject: [PATCH 3/7] formatted according to JuliaFormatter --- test/simplegraphs/generators/staticgraphs.jl | 54 +------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/test/simplegraphs/generators/staticgraphs.jl b/test/simplegraphs/generators/staticgraphs.jl index 6cb9649ad..e85a637fa 100644 --- a/test/simplegraphs/generators/staticgraphs.jl +++ b/test/simplegraphs/generators/staticgraphs.jl @@ -413,58 +413,8 @@ @testset "Regular Trees" begin g = @inferred(regular_tree(3, 3)) - I = [ - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13 - ] - J = [ - 2, - 3, - 4, - 1, - 5, - 6, - 7, - 8, - 1, - 9, - 10, - 1, - 11, - 12, - 13, - 2, - 2, - 2, - 3, - 3, - 3, - 4, - 4, - 4 - ] + I = [1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + J = [2, 3, 4, 1, 5, 6, 7, 8, 1, 9, 10, 1, 11, 12, 13, 2, 2, 2, 3, 3, 3, 4, 4, 4] V = ones(Int, length(I)) Adj = sparse(I, J, V) @test Adj == sparse(g) From 9a0fb29cda97999e4b6e877cfc0b6fb46ea84015 Mon Sep 17 00:00:00 2001 From: stecrotti Date: Wed, 23 Nov 2022 15:57:01 +0100 Subject: [PATCH 4/7] fix error in docstring --- src/SimpleGraphs/generators/staticgraphs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SimpleGraphs/generators/staticgraphs.jl b/src/SimpleGraphs/generators/staticgraphs.jl index a9fc43ddc..b5e3e1d37 100644 --- a/src/SimpleGraphs/generators/staticgraphs.jl +++ b/src/SimpleGraphs/generators/staticgraphs.jl @@ -539,7 +539,7 @@ end """ regular_tree(k::Integer, z::integer) -Create a [k-regular tree](https://en.wikipedia.org/wiki/Bethe_lattice), +Create a [regular tree](https://en.wikipedia.org/wiki/Bethe_lattice), also known as Bethe Lattice or Cayley Tree, of depth `k` and degree `z`. From f4411979e9f7499a709a3053ab3992fd77636190 Mon Sep 17 00:00:00 2001 From: stecrotti Date: Thu, 24 Nov 2022 13:51:40 +0100 Subject: [PATCH 5/7] add test for domain error --- test/simplegraphs/generators/staticgraphs.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/simplegraphs/generators/staticgraphs.jl b/test/simplegraphs/generators/staticgraphs.jl index e85a637fa..46b845096 100644 --- a/test/simplegraphs/generators/staticgraphs.jl +++ b/test/simplegraphs/generators/staticgraphs.jl @@ -419,6 +419,7 @@ Adj = sparse(I, J, V) @test Adj == sparse(g) @test isvalid_simplegraph(g) + @test_throws DomainError regular_tree(Int8(4), Int8(4)) # test that setting z = 2 recovers a binary tree @test all(regular_tree(k, 2) == binary_tree(k) for k in 0:10) end From ec15727c80177ccbef2933b52987b743bd499cb0 Mon Sep 17 00:00:00 2001 From: stecrotti Date: Tue, 29 Nov 2022 16:44:38 +0100 Subject: [PATCH 6/7] new signature, InexactError, works for Int types --- src/SimpleGraphs/generators/staticgraphs.jl | 36 ++++++++++++-------- test/simplegraphs/generators/staticgraphs.jl | 8 +++-- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/SimpleGraphs/generators/staticgraphs.jl b/src/SimpleGraphs/generators/staticgraphs.jl index b5e3e1d37..ead1d1623 100644 --- a/src/SimpleGraphs/generators/staticgraphs.jl +++ b/src/SimpleGraphs/generators/staticgraphs.jl @@ -537,53 +537,59 @@ function double_binary_tree(k::Integer) end """ - regular_tree(k::Integer, z::integer) + regular_tree([T=Int64, ], k::Integer, z::integer) -Create a [regular tree](https://en.wikipedia.org/wiki/Bethe_lattice), -also known as Bethe Lattice or Cayley Tree, -of depth `k` and degree `z`. +Create a regular tree or [perfect z-ary tree](https://en.wikipedia.org/wiki/M-ary_tree#Types_of_m-ary_trees): +a `k`-level tree where all nodes except the leaves have exactly `z` children. +For `z = 2` one recovers a binary tree. # Examples ```jldoctest julia> regular_tree(4, 3) {40, 39} undirected simple Int64 graph +julia> regular_tree(Int8, 3, 2) +{7, 6} undirected simple Int8 graph + julia> regular_tree(5, 2) == binary_tree(5) true ``` """ -function regular_tree(k::T, z::T) where {T<:Integer} - k <= 0 && return SimpleGraph(0) - k == 1 && return SimpleGraph(1) - if Graphs.isbounded(k) && BigInt(z)^k - 1 > typemax(k) - throw(DomainError(k, "z^k - 1 not representable by type $T")) +function regular_tree(T::Type{<:Integer}, k::Integer, z::Integer) + z <= 0 && throw(DomainError(z, "number of children must be positive")) + z == 1 && return path_graph(T(k)) + k <= 0 && return SimpleGraph(zero(T)) + k == 1 && return SimpleGraph(one(T)) + if Graphs.isbounded(k) && (BigInt(z)^k - 1) ÷ (z - 1) > typemax(T) + throw(InexactError(:convert, T, (BigInt(z)^k - 1) ÷ (z - 1))) end n = T((z^k - 1) / (z - 1)) - ne = Int(n - 1) + ne = n - 1 fadjlist = Vector{Vector{T}}(undef, n) - @inbounds fadjlist[1] = convert.(T, 2:(z + 1)) @inbounds for l in 2:(k - 1) - w = Int((z^(l - 1) - 1) / (z - 1)) + w = (z^(l - 1) - 1) ÷ (z - 1) x = w + z^(l - 1) @simd for i in 1:(z^(l - 1)) j = w + i fadjlist[j] = [ - ceil(T, (j - x) / z) + w + T(ceil((j - x) / z) + w) convert.(T, (x + (i - 1) * z + 1):(x + i * z)) ] end end l = k - w = Int((z^(l - 1) - 1) / (z - 1)) + w = (z^(l - 1) - 1) ÷ (z - 1) x = w + z^(l - 1) @inbounds @simd for j in (w + 1):x - fadjlist[j] = T[ceil(Int, (j - x) / z) + w] + fadjlist[j] = T[ceil((j - x) / z) + w] end return SimpleGraph(ne, fadjlist) end +regular_tree(k::Integer, z::Integer) = regular_tree(Int64, k, z) + """ roach_graph(k) diff --git a/test/simplegraphs/generators/staticgraphs.jl b/test/simplegraphs/generators/staticgraphs.jl index 46b845096..b1e7c9cf4 100644 --- a/test/simplegraphs/generators/staticgraphs.jl +++ b/test/simplegraphs/generators/staticgraphs.jl @@ -419,8 +419,12 @@ Adj = sparse(I, J, V) @test Adj == sparse(g) @test isvalid_simplegraph(g) - @test_throws DomainError regular_tree(Int8(4), Int8(4)) - # test that setting z = 2 recovers a binary tree + @test_throws InexactError regular_tree(Int8, 4, 5) + g = @inferred(regular_tree(Int16, 4, 5)) + @test isvalid_simplegraph(g) + # test that z = 1 recovers a path graph + @test all(regular_tree(k, 1) == path_graph(k) for k in 0:10) + # test that z = 2 recovers a binary tree @test all(regular_tree(k, 2) == binary_tree(k) for k in 0:10) end From b26cf91325b2d44d812f078381c43da808bd7217 Mon Sep 17 00:00:00 2001 From: stecrotti Date: Mon, 19 Dec 2022 10:18:27 +0100 Subject: [PATCH 7/7] uniform signature style, fix overflow --- src/SimpleGraphs/generators/staticgraphs.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/SimpleGraphs/generators/staticgraphs.jl b/src/SimpleGraphs/generators/staticgraphs.jl index ead1d1623..251499294 100644 --- a/src/SimpleGraphs/generators/staticgraphs.jl +++ b/src/SimpleGraphs/generators/staticgraphs.jl @@ -537,11 +537,12 @@ function double_binary_tree(k::Integer) end """ - regular_tree([T=Int64, ], k::Integer, z::integer) + regular_tree([T::Type], k, z) Create a regular tree or [perfect z-ary tree](https://en.wikipedia.org/wiki/M-ary_tree#Types_of_m-ary_trees): a `k`-level tree where all nodes except the leaves have exactly `z` children. For `z = 2` one recovers a binary tree. +The optional `T` argument specifies the element type, which defaults to `Int64`. # Examples ```jldoctest @@ -560,11 +561,12 @@ function regular_tree(T::Type{<:Integer}, k::Integer, z::Integer) z == 1 && return path_graph(T(k)) k <= 0 && return SimpleGraph(zero(T)) k == 1 && return SimpleGraph(one(T)) - if Graphs.isbounded(k) && (BigInt(z)^k - 1) ÷ (z - 1) > typemax(T) - throw(InexactError(:convert, T, (BigInt(z)^k - 1) ÷ (z - 1))) + nbig = (BigInt(z)^k - 1) ÷ (z - 1) + if Graphs.isbounded(k) && nbig > typemax(T) + throw(InexactError(:convert, T, nbig)) end - n = T((z^k - 1) / (z - 1)) + n = T(nbig) ne = n - 1 fadjlist = Vector{Vector{T}}(undef, n) @inbounds fadjlist[1] = convert.(T, 2:(z + 1))