Skip to content

Commit e40088a

Browse files
YingboMaranocha
authored andcommitted
Optimize (#2)
* Make `subtrees` function type stable * Add `rootedtree` * Fix logic
1 parent 19139c7 commit e40088a

File tree

2 files changed

+64
-64
lines changed

2 files changed

+64
-64
lines changed

src/RootedTrees.jl

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using LinearAlgebra
66
import Base: show, isless, ==, iterate, copy
77

88

9-
export RootedTree, RootedTreeIterator
9+
export rootedtree, RootedTreeIterator
1010

1111
export α, β, γ, σ, order, residual_order_condition, elementary_weight, derivative_weight
1212

@@ -15,7 +15,7 @@ export count_trees
1515

1616

1717
"""
18-
RootedTree{T<:Integer}
18+
RootedTree
1919
2020
Represents a rooted tree using its level sequence.
2121
@@ -24,18 +24,33 @@ Reference:
2424
"Constant time generation of rooted trees."
2525
SIAM Journal on Computing 9.4 (1980): 706-712.
2626
"""
27-
struct RootedTree{T<:Integer, V<:AbstractVector}
27+
mutable struct RootedTree{T<:Integer, V<:AbstractVector}
2828
level_sequence::V
29+
iscanonical::Bool
2930
end
3031

31-
function RootedTree(level_sequence::AbstractVector)
32+
function RootedTree(level_sequence::AbstractVector, iscanonical=false)
3233
T = eltype(level_sequence)
3334
V = typeof(level_sequence)
34-
RootedTree{T,V}(level_sequence)
35+
RootedTree{T,V}(level_sequence, iscanonical)
3536
end
37+
38+
"""
39+
rootedtree
40+
41+
Construct a canonical `RootedTree` object from a level sequence.
42+
43+
Reference:
44+
Beyer, Terry, and Sandra Mitchell Hedetniemi.
45+
"Constant time generation of rooted trees."
46+
SIAM Journal on Computing 9.4 (1980): 706-712.
47+
"""
48+
rootedtree(level_sequence::AbstractVector) = canonical_representation(RootedTree(level_sequence))
49+
50+
iscanonical(t::RootedTree) = t.iscanonical
3651
#TODO: Validate rooted tree in constructor?
3752

38-
copy(t::RootedTree) = RootedTree(copy(t.level_sequence))
53+
copy(t::RootedTree) = RootedTree(copy(t.level_sequence), t.iscanonical)
3954

4055

4156
# #function RootedTree(sequence::Vector{T}, valid::Bool)
@@ -86,7 +101,7 @@ function ==(t1::RootedTree, t2::RootedTree)
86101
end
87102

88103

89-
# generation and caonical representation
104+
# generation and canonical representation
90105
"""
91106
canonical_representation!(t::RootedTree)
92107
@@ -105,6 +120,7 @@ function canonical_representation!(t::RootedTree)
105120
t.level_sequence[i:i+order(τ)-1] = τ.level_sequence[:]
106121
i += order(τ)
107122
end
123+
t.iscanonical = true
108124

109125
t
110126
end
@@ -133,7 +149,7 @@ struct RootedTreeIterator{T<:Integer}
133149
t::RootedTree{T,Vector{T}}
134150

135151
function RootedTreeIterator(order::T) where {T<:Integer}
136-
new{T}(order, RootedTree(Vector{T}(one(T):order)))
152+
new{T}(order, RootedTree(Vector{T}(one(T):order), true))
137153
end
138154
end
139155

@@ -154,6 +170,7 @@ function iterate(iter::RootedTreeIterator{T}, state) where {T}
154170
p = i
155171
end
156172
end
173+
p == 1 && return nothing
157174

158175
level_q = iter.t.level_sequence[p] - one(T)
159176
@inbounds for i in 1:p
@@ -162,8 +179,6 @@ function iterate(iter::RootedTreeIterator{T}, state) where {T}
162179
end
163180
end
164181

165-
p == 1 && return nothing
166-
167182
@inbounds for i in p:length(iter.t.level_sequence)
168183
iter.t.level_sequence[i] = iter.t.level_sequence[i - (p-q)]
169184
end
@@ -192,6 +207,7 @@ end
192207
struct Subtrees{T<:Integer} <: AbstractVector{RootedTree{T}}
193208
level_sequence::Vector{T}
194209
indices::Vector{T}
210+
iscanonical::Bool
195211

196212
function Subtrees(t::RootedTree{T}) where {T}
197213
level_sequence = t.level_sequence
@@ -211,12 +227,12 @@ struct Subtrees{T<:Integer} <: AbstractVector{RootedTree{T}}
211227
# in order to get the stopping index for the last subtree
212228
push!(indices, length(level_sequence)+1)
213229

214-
new{T}(level_sequence, indices)
230+
new{T}(level_sequence, indices, iscanonical(t))
215231
end
216232
end
217233

218234
Base.size(s::Subtrees) = (length(s.indices)-1, )
219-
Base.getindex(s::Subtrees, i::Int) = RootedTree(view(s.level_sequence, s.indices[i]:s.indices[i+1]-1))
235+
Base.getindex(s::Subtrees, i::Int) = RootedTree(view(s.level_sequence, s.indices[i]:s.indices[i+1]-1), s.iscanonical)
220236

221237

222238
"""
@@ -225,7 +241,7 @@ Base.getindex(s::Subtrees, i::Int) = RootedTree(view(s.level_sequence, s.indices
225241
Returns a vector of all subtrees of `t`.
226242
"""
227243
function subtrees(t::RootedTree{T}) where {T}
228-
subtr = RootedTree{T}[]
244+
subtr = typeof(t)[]
229245

230246
if length(t.level_sequence) < 2
231247
return subtr
@@ -255,25 +271,22 @@ order(t::RootedTree) = length(t.level_sequence)
255271

256272

257273
"""
258-
σ(t::RootedTree, is_canonical::Bool = false)
274+
σ(t::RootedTree)
259275
260276
The symmetry `σ` of a rooted tree `t`, i.e. the order of the group of automorphisms
261277
on a particular labelling (of the vertices) of `t`.
262278
263-
If `is_canonical`, it is assumed that `t` is given using the canonical
264-
representation.
265-
266279
Reference: Section 301 of
267280
Butcher, John Charles.
268281
Numerical methods for ordinary differential equations.
269282
John Wiley & Sons, 2008.
270283
"""
271-
function σ(t::RootedTree, is_canonical=false)
284+
function σ(t::RootedTree)
272285
if order(t) == 1 || order(t) == 2
273286
return 1
274287
end
275288

276-
if !is_canonical
289+
if !iscanonical(t)
277290
t = canonical_representation(t)
278291
end
279292

@@ -325,16 +338,13 @@ end
325338
326339
The number of monotonic labellings of `t` not equivalent under the symmetry group.
327340
328-
If `is_canonical`, it is assumed that `t` is given using the canonical
329-
representation.
330-
331341
Reference: Section 302 of
332342
Butcher, John Charles.
333343
Numerical methods for ordinary differential equations.
334344
John Wiley & Sons, 2008.
335345
"""
336-
function α(t::RootedTree, is_canonical=false)
337-
div(factorial(order(t)), σ(t, is_canonical)*γ(t))
346+
function α(t::RootedTree)
347+
div(factorial(order(t)), σ(t)*γ(t))
338348
end
339349

340350

@@ -343,16 +353,13 @@ end
343353
344354
The total number of labellings of `t` not equivalent under the symmetry group.
345355
346-
If `is_canonical`, it is assumed that `t` is given using the canonical
347-
representation.
348-
349356
Reference: Section 302 of
350357
Butcher, John Charles.
351358
Numerical methods for ordinary differential equations.
352359
John Wiley & Sons, 2008.
353360
"""
354-
function β(t::RootedTree, is_canonical=false)
355-
div(factorial(order(t)), σ(t, is_canonical))
361+
function β(t::RootedTree)
362+
div(factorial(order(t)), σ(t))
356363
end
357364

358365

@@ -404,27 +411,24 @@ end
404411

405412

406413
"""
407-
residual_order_condition(t::RootedTree, A, b, c, is_canonical=false)
414+
residual_order_condition(t::RootedTree, A, b, c)
408415
409416
The residual of the order condition
410417
`(Φ(t) - 1/γ(t)) / σ(t)`
411418
with elementary weight `Φ(t)`, density `γ(t)`, and symmetry `σ(t)` of the
412419
rooted tree `t` for the Runge-Kutta method with Butcher coefficients
413420
`A, b, c`.
414421
415-
If `is_canonical`, it is assumed that `t` is given using the canonical
416-
representation.
417-
418422
Reference: Section 315 of
419423
Butcher, John Charles.
420424
Numerical methods for ordinary differential equations.
421425
John Wiley & Sons, 2008.
422426
"""
423-
function residual_order_condition(t::RootedTree, A, b, c, is_canonical=false)
427+
function residual_order_condition(t::RootedTree, A, b, c)
424428
ew = elementary_weight(t, A, b, c)
425429
T = typeof(ew)
426430

427-
(ew - one(T) / γ(t)) / σ(t, is_canonical)
431+
(ew - one(T) / γ(t)) / σ(t)
428432
end
429433

430434

0 commit comments

Comments
 (0)