Skip to content

Commit 98942df

Browse files
stecrottistecrottiKrastanov
authored
Add regular tree generator (#197)
Co-authored-by: stecrotti <ruggentipini@gmail.com> Co-authored-by: Stefan Krastanov <github.acc@krastanov.org>
1 parent 82fee84 commit 98942df

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

src/Graphs.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ export
352352
cycle_digraph,
353353
binary_tree,
354354
double_binary_tree,
355+
regular_tree,
355356
roach_graph,
356357
clique_graph,
357358
ladder_graph,

src/SimpleGraphs/SimpleGraphs.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export AbstractSimpleGraph,
9393
cycle_digraph,
9494
binary_tree,
9595
double_binary_tree,
96+
regular_tree,
9697
roach_graph,
9798
clique_graph,
9899
barbell_graph,

src/SimpleGraphs/generators/staticgraphs.jl

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,64 @@ function double_binary_tree(k::Integer)
568568
return g
569569
end
570570

571+
"""
572+
regular_tree([T::Type], k, z)
573+
574+
Create a regular tree or [perfect z-ary tree](https://en.wikipedia.org/wiki/M-ary_tree#Types_of_m-ary_trees):
575+
a `k`-level tree where all nodes except the leaves have exactly `z` children.
576+
For `z = 2` one recovers a binary tree.
577+
The optional `T` argument specifies the element type, which defaults to `Int64`.
578+
579+
# Examples
580+
```jldoctest
581+
julia> using Graphs
582+
583+
julia> regular_tree(4, 3)
584+
{40, 39} undirected simple Int64 graph
585+
586+
julia> regular_tree(Int8, 3, 2)
587+
{7, 6} undirected simple Int8 graph
588+
589+
julia> regular_tree(5, 2) == binary_tree(5)
590+
true
591+
```
592+
"""
593+
function regular_tree(T::Type{<:Integer}, k::Integer, z::Integer)
594+
z <= 0 && throw(DomainError(z, "number of children must be positive"))
595+
z == 1 && return path_graph(T(k))
596+
k <= 0 && return SimpleGraph(zero(T))
597+
k == 1 && return SimpleGraph(one(T))
598+
nbig = (BigInt(z)^k - 1) ÷ (z - 1)
599+
if Graphs.isbounded(k) && nbig > typemax(T)
600+
throw(InexactError(:convert, T, nbig))
601+
end
602+
603+
n = T(nbig)
604+
ne = n - 1
605+
fadjlist = Vector{Vector{T}}(undef, n)
606+
@inbounds fadjlist[1] = convert.(T, 2:(z + 1))
607+
@inbounds for l in 2:(k - 1)
608+
w = (z^(l - 1) - 1) ÷ (z - 1)
609+
x = w + z^(l - 1)
610+
@simd for i in 1:(z ^ (l - 1))
611+
j = w + i
612+
fadjlist[j] = [
613+
T(ceil((j - x) / z) + w)
614+
convert.(T, (x + (i - 1) * z + 1):(x + i * z))
615+
]
616+
end
617+
end
618+
l = k
619+
w = (z^(l - 1) - 1) ÷ (z - 1)
620+
x = w + z^(l - 1)
621+
@inbounds @simd for j in (w + 1):x
622+
fadjlist[j] = T[ceil((j - x) / z) + w]
623+
end
624+
return SimpleGraph(ne, fadjlist)
625+
end
626+
627+
regular_tree(k::Integer, z::Integer) = regular_tree(Int64, k, z)
628+
571629
"""
572630
roach_graph(k)
573631

test/simplegraphs/generators/staticgraphs.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,23 @@
411411
@test isvalid_simplegraph(g)
412412
end
413413

414+
@testset "Regular Trees" begin
415+
g = @inferred(regular_tree(3, 3))
416+
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]
417+
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]
418+
V = ones(Int, length(I))
419+
Adj = sparse(I, J, V)
420+
@test Adj == sparse(g)
421+
@test isvalid_simplegraph(g)
422+
@test_throws InexactError regular_tree(Int8, 4, 5)
423+
g = @inferred(regular_tree(Int16, 4, 5))
424+
@test isvalid_simplegraph(g)
425+
# test that z = 1 recovers a path graph
426+
@test all(regular_tree(k, 1) == path_graph(k) for k in 0:10)
427+
# test that z = 2 recovers a binary tree
428+
@test all(regular_tree(k, 2) == binary_tree(k) for k in 0:10)
429+
end
430+
414431
@testset "Roach Graphs" begin
415432
rg3 = @inferred(roach_graph(3))
416433
# [3]

0 commit comments

Comments
 (0)