Skip to content

Commit ef69c47

Browse files
authored
butcher_product! for colored trees (#176)
* butcher_product! for colored trees * fix * no buffers required * tests for colored trees * test allocations
1 parent 26eeb55 commit ef69c47

File tree

4 files changed

+83
-3
lines changed

4 files changed

+83
-3
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "RootedTrees"
22
uuid = "47965b36-3f3e-11e9-0dcf-4570dfd42a8c"
33
authors = ["Hendrik Ranocha <mail@ranocha.de> and contributors"]
4-
version = "2.22.0"
4+
version = "2.23.0"
55

66
[deps]
77
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"

src/RootedTrees.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,7 @@ function Base.:∘(t1::RootedTree, t2::RootedTree)
13581358
end
13591359

13601360
"""
1361-
butcher_product!(t::RootedTree, t1::RootedTree, t2::RootedTree)
1361+
butcher_product!(t, t1, t2)
13621362
13631363
Compute the non-associative Butcher product `t = t1 ∘ t2` of rooted trees
13641364
in-place. It is formed by adding an edge from the root of `t1` to the root
@@ -1371,7 +1371,8 @@ Reference: Section 301 of
13711371
Numerical methods for ordinary differential equations.
13721372
John Wiley & Sons, 2016.
13731373
"""
1374-
function butcher_product!(t::RootedTree, t1::RootedTree, t2::RootedTree)
1374+
function butcher_product!(t::RootedTree,
1375+
t1::RootedTree, t2::RootedTree)
13751376
offset = first(t1.level_sequence) - first(t2.level_sequence) + 1
13761377

13771378
unsafe_resize!(t, order(t1) + order(t2))

src/colored_trees.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,31 @@ function Base.:∘(t1::ColoredRootedTree, t2::ColoredRootedTree)
568568
rootedtree(level_sequence, color_sequence)
569569
end
570570

571+
function butcher_product!(t::ColoredRootedTree,
572+
t1::ColoredRootedTree, t2::ColoredRootedTree)
573+
offset = first(t1.level_sequence) - first(t2.level_sequence) + 1
574+
575+
unsafe_resize!(t, order(t1) + order(t2))
576+
i = firstindex(t.level_sequence)
577+
j = firstindex(t1.level_sequence)
578+
while j <= lastindex(t1.level_sequence)
579+
t.level_sequence[i] = t1.level_sequence[j]
580+
t.color_sequence[i] = t1.color_sequence[j]
581+
i += 1
582+
j += 1
583+
end
584+
j = firstindex(t2.level_sequence)
585+
while j <= lastindex(t2.level_sequence)
586+
t.level_sequence[i] = t2.level_sequence[j] + offset
587+
t.color_sequence[i] = t2.color_sequence[j]
588+
i += 1
589+
j += 1
590+
end
591+
592+
canonical_representation!(t)
593+
return t
594+
end
595+
571596
function butcher_representation(t::ColoredRootedTree, normalize::Bool = true;
572597
colormap = _colormap_butcher_representation(t))
573598
if order(t) == 0

test/runtests.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ using Aqua: Aqua
314314
@inferred t1 t1
315315
t_result = copy(t1)
316316
@inferred butcher_product!(t_result, t1, t1)
317+
@test @allocated(butcher_product!(t_result, t1, t1)) == 0
317318
@test t_result == t1 t1
318319

319320
t2 = rootedtree([1, 2])
@@ -324,6 +325,7 @@ using Aqua: Aqua
324325
@test β(t2) == α(t2) * γ(t2)
325326
@test t2 == t1 t1
326327
@inferred butcher_product!(t_result, t1, t1)
328+
@test @allocated(butcher_product!(t_result, t1, t1)) == 0
327329
@test t2 == t_result
328330
@test butcher_representation(t2) == "[τ]"
329331
latex_string = "\\rootedtree[.[.]]"
@@ -341,6 +343,7 @@ using Aqua: Aqua
341343
@test β(t3) == α(t3) * γ(t3)
342344
@test t3 == t2 t1
343345
@inferred butcher_product!(t_result, t2, t1)
346+
@test @allocated(butcher_product!(t_result, t2, t1)) == 0
344347
@test t3 == t_result
345348
@test butcher_representation(t3) == "[τ²]"
346349
latex_string = "\\rootedtree[.[.][.]]"
@@ -358,6 +361,7 @@ using Aqua: Aqua
358361
@test β(t4) == α(t4) * γ(t4)
359362
@test t4 == t1 t2
360363
@inferred butcher_product!(t_result, t1, t2)
364+
@test @allocated(butcher_product!(t_result, t1, t2)) == 0
361365
@test t4 == t_result
362366
@test butcher_representation(t4) == "[[τ]]"
363367
latex_string = "\\rootedtree[.[.[.]]]"
@@ -375,6 +379,7 @@ using Aqua: Aqua
375379
@test β(t5) == α(t5) * γ(t5)
376380
@test t5 == t3 t1
377381
@inferred butcher_product!(t_result, t3, t1)
382+
@test @allocated(butcher_product!(t_result, t3, t1)) == 0
378383
@test t5 == t_result
379384
@test butcher_representation(t5) == "[τ³]"
380385
@test RootedTrees.subtrees(t5) ==
@@ -392,8 +397,10 @@ using Aqua: Aqua
392397
@test β(t6) == α(t6) * γ(t6)
393398
@test t6 == t2 t2 == t4 t1
394399
@inferred butcher_product!(t_result, t2, t2)
400+
@test @allocated(butcher_product!(t_result, t2, t2)) == 0
395401
@test t6 == t_result
396402
@inferred butcher_product!(t_result, t4, t1)
403+
@test @allocated(butcher_product!(t_result, t4, t1)) == 0
397404
@test t6 == t_result
398405
@test butcher_representation(t6) == "[[τ]τ]"
399406
@test RootedTrees.subtrees(t6) == [rootedtree([2, 3]), rootedtree([2])]
@@ -409,6 +416,7 @@ using Aqua: Aqua
409416
@test β(t7) == α(t7) * γ(t7)
410417
@test t7 == t1 t3
411418
@inferred butcher_product!(t_result, t1, t3)
419+
@test @allocated(butcher_product!(t_result, t1, t3)) == 0
412420
@test t7 == t_result
413421
@test butcher_representation(t7) == "[[τ²]]"
414422
@test elementary_differential_latexstring(t7) ==
@@ -422,6 +430,7 @@ using Aqua: Aqua
422430
@test α(t8) == 1
423431
@test t8 == t1 t4
424432
@inferred butcher_product!(t_result, t1, t4)
433+
@test @allocated(butcher_product!(t_result, t1, t4)) == 0
425434
@test t8 == t_result
426435
@test butcher_representation(t8) == "[[[τ]]]"
427436
@test elementary_differential_latexstring(t8) ==
@@ -437,6 +446,7 @@ using Aqua: Aqua
437446
@test β(t9) == α(t9) * γ(t9)
438447
@test t9 == t5 t1
439448
@inferred butcher_product!(t_result, t5, t1)
449+
@test @allocated(butcher_product!(t_result, t5, t1)) == 0
440450
@test t9 == t_result
441451
@test butcher_representation(t9) == "[τ⁴]"
442452
@test elementary_differential_latexstring(t9) == L"$f^{(4)}(f, f, f, f)$"
@@ -450,8 +460,10 @@ using Aqua: Aqua
450460
@test β(t10) == α(t10) * γ(t10)
451461
@test t10 == t3 t2 == t6 t1
452462
@inferred butcher_product!(t_result, t3, t2)
463+
@test @allocated(butcher_product!(t_result, t3, t2)) == 0
453464
@test t10 == t_result
454465
@inferred butcher_product!(t_result, t6, t1)
466+
@test @allocated(butcher_product!(t_result, t6, t1)) == 0
455467
@test t10 == t_result
456468
@test butcher_representation(t10) == "[[τ]τ²]"
457469
@test elementary_differential_latexstring(t10) ==
@@ -466,8 +478,10 @@ using Aqua: Aqua
466478
@test α(t11) == 4
467479
@test t11 == t2 t3 == t7 t1
468480
@inferred butcher_product!(t_result, t2, t3)
481+
@test @allocated(butcher_product!(t_result, t2, t3)) == 0
469482
@test t11 == t_result
470483
@inferred butcher_product!(t_result, t7, t1)
484+
@test @allocated(butcher_product!(t_result, t7, t1)) == 0
471485
@test t11 == t_result
472486
@test butcher_representation(t11) == "[[τ²]τ]"
473487
@test elementary_differential_latexstring(t11) ==
@@ -483,8 +497,10 @@ using Aqua: Aqua
483497
@test β(t12) == α(t12) * γ(t12)
484498
@test t12 == t2 t4 == t8 t1
485499
@inferred butcher_product!(t_result, t2, t4)
500+
@test @allocated(butcher_product!(t_result, t2, t4)) == 0
486501
@test t12 == t_result
487502
@inferred butcher_product!(t_result, t8, t1)
503+
@test @allocated(butcher_product!(t_result, t8, t1)) == 0
488504
@test t12 == t_result
489505
@test butcher_representation(t12) == "[[[τ]]τ]"
490506
@test elementary_differential_latexstring(t12) ==
@@ -500,6 +516,7 @@ using Aqua: Aqua
500516
@test β(t13) == α(t13) * γ(t13)
501517
@test t13 == t4 t2
502518
@inferred butcher_product!(t_result, t4, t2)
519+
@test @allocated(butcher_product!(t_result, t4, t2)) == 0
503520
@test t13 == t_result
504521
@test butcher_representation(t13) == "[[τ][τ]]"
505522
@test elementary_differential_latexstring(t13) ==
@@ -515,6 +532,7 @@ using Aqua: Aqua
515532
@test β(t14) == α(t14) * γ(t14)
516533
@test t14 == t1 t5
517534
@inferred butcher_product!(t_result, t1, t5)
535+
@test @allocated(butcher_product!(t_result, t1, t5)) == 0
518536
@test t14 == t_result
519537
@test butcher_representation(t14) == "[[τ³]]"
520538
@test elementary_differential_latexstring(t14) ==
@@ -530,6 +548,7 @@ using Aqua: Aqua
530548
@test β(t15) == α(t15) * γ(t15)
531549
@test t15 == t1 t6
532550
@inferred butcher_product!(t_result, t1, t6)
551+
@test @allocated(butcher_product!(t_result, t1, t6)) == 0
533552
@test t15 == t_result
534553
@test butcher_representation(t15) == "[[[τ]τ]]"
535554
@test elementary_differential_latexstring(t15) ==
@@ -545,6 +564,7 @@ using Aqua: Aqua
545564
@test β(t16) == α(t16) * γ(t16)
546565
@test t16 == t1 t7
547566
@inferred butcher_product!(t_result, t1, t7)
567+
@test @allocated(butcher_product!(t_result, t1, t7)) == 0
548568
@test t16 == t_result
549569
@test butcher_representation(t16) == "[[[τ²]]]"
550570
@test elementary_differential_latexstring(t16) ==
@@ -560,6 +580,7 @@ using Aqua: Aqua
560580
@test β(t17) == α(t17) * γ(t17)
561581
@test t17 == t1 t8
562582
@inferred butcher_product!(t_result, t1, t8)
583+
@test @allocated(butcher_product!(t_result, t1, t8)) == 0
563584
@test t17 == t_result
564585
@test butcher_representation(t17) == "[[[[τ]]]]"
565586
@test elementary_differential_latexstring(t17) ==
@@ -1095,6 +1116,39 @@ using Aqua: Aqua
10951116
end
10961117
end
10971118

1119+
@testset "Butcher product" begin
1120+
t1_0 = @inferred rootedtree([1], Bool[0])
1121+
t1_1 = @inferred rootedtree([1], Bool[1])
1122+
@inferred t1_0 t1_0
1123+
t_result = copy(t1_0)
1124+
@inferred butcher_product!(t_result, t1_0, t1_0)
1125+
@test_broken @allocated(butcher_product!(t_result, t1_0, t1_0)) == 0
1126+
@test t_result == t1_0 t1_0
1127+
@test t_result == rootedtree([1, 2], Bool[0, 0])
1128+
@inferred butcher_product!(t_result, t1_1, t1_0)
1129+
@test_broken @allocated(butcher_product!(t_result, t1_1, t1_0)) == 0
1130+
@test t_result == t1_1 t1_0
1131+
@test t_result == rootedtree([1, 2], Bool[1, 0])
1132+
@inferred butcher_product!(t_result, t1_0, t1_1)
1133+
@test_broken @allocated(butcher_product!(t_result, t1_0, t1_1)) == 0
1134+
@test t_result == t1_0 t1_1
1135+
@test t_result == rootedtree([1, 2], Bool[0, 1])
1136+
@inferred butcher_product!(t_result, t1_1, t1_1)
1137+
@test_broken @allocated(butcher_product!(t_result, t1_1, t1_1)) == 0
1138+
@test t_result == t1_1 t1_1
1139+
@test t_result == rootedtree([1, 2], Bool[1, 1])
1140+
1141+
t2_0 = @inferred rootedtree([1, 2], Bool[0, 0])
1142+
@inferred butcher_product!(t_result, t2_0, t1_0)
1143+
@test_broken @allocated(butcher_product!(t_result, t2_0, t1_0)) == 0
1144+
@test t_result == t2_0 t1_0
1145+
@test t_result == rootedtree([1, 2, 2], Bool[0, 0, 0])
1146+
@inferred butcher_product!(t_result, t2_0, t1_1)
1147+
@test_broken @allocated(butcher_product!(t_result, t2_0, t1_1)) == 0
1148+
@test t_result == t2_0 t1_1
1149+
@test t_result == rootedtree([1, 2, 2], Bool[0, 0, 1])
1150+
end
1151+
10981152
@testset "latexify" begin
10991153
@testset "default style" begin
11001154
let t = rootedtree(Int[], Bool[])

0 commit comments

Comments
 (0)