Skip to content

Commit fb51bc3

Browse files
authored
new latexify setup to support colored trees (#100)
* change LaTeX representation of rooted trees * latexify for bicolored rooted trees * new latexify example in the docs * format * fix docstring
1 parent ff066ce commit fb51bc3

File tree

6 files changed

+112
-46
lines changed

6 files changed

+112
-46
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.15.2"
4+
version = "2.16.0"
55

66
[deps]
77
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ Additionally, functions on trees connected to Runge-Kutta methods are implemente
103103

104104
## Brief Changelog
105105

106+
- v2.16: The LaTeX printing of rooted trees changed to allow representing
107+
colored rooted trees. Please update your LaTeX preamble as described in
108+
the docstring of `RootedTrees.latexify`.
106109
- v2.0: Rooted trees are considered up to isomorphisms introduced by shifting
107110
each coefficient of their level sequence by the same number.
108111

docs/src/tutorials/basics.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ for t in BicoloredRootedTreeIterator(3)
123123
end
124124
```
125125

126+
[`RootedTrees.latexify`](@ref) also supports bicolored rooted trees:
127+
128+
```@example basics
129+
for t in BicoloredRootedTreeIterator(3)
130+
println(RootedTrees.latexify(t))
131+
end
132+
```
133+
126134
```@example basics
127135
using Plots
128136
t = rootedtree([1, 2, 3, 3, 2, 2], Bool[0, 0, 1, 0, 1, 0])

src/RootedTrees.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,9 @@ Section 2.3 of
658658
[DOI: 10.1007/s10208-010-9065-1](https://doi.org/10.1007/s10208-010-9065-1)
659659
"""
660660
function partition_forest(t::RootedTree, edge_set)
661-
@boundscheck begin @assert length(t.level_sequence) == length(edge_set) + 1 end
661+
@boundscheck begin
662+
@assert length(t.level_sequence) == length(edge_set) + 1
663+
end
662664

663665
level_sequence = copy(t.level_sequence)
664666
edge_set_copy = copy(edge_set)
@@ -800,7 +802,9 @@ Section 2.3 (and Section 6.1 for colored trees) of
800802
[DOI: 10.1007/s10208-010-9065-1](https://doi.org/10.1007/s10208-010-9065-1)
801803
"""
802804
function partition_skeleton(t::AbstractRootedTree, edge_set)
803-
@boundscheck begin @assert order(t) == length(edge_set) + 1 end
805+
@boundscheck begin
806+
@assert order(t) == length(edge_set) + 1
807+
end
804808

805809
edge_set_copy = copy(edge_set)
806810
skeleton = copy(t)

src/latexify.jl

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,79 @@
11

22
"""
3-
latexify(t::RootedTree)
3+
latexify(t::Union{RootedTree, BicoloredRootedTree})
44
55
Return a LaTeX representation of the rooted tree `t`. This makes use of the
66
LaTeX package [forest](https://ctan.org/pkg/forest) and assumes that you use
77
the following LaTeX code in the preamble.
88
99
```
10-
% Butcher trees, cf. https://tex.stackexchange.com/questions/283343/butcher-trees-in-tikz
10+
% Classical and colored Butcher trees based on
11+
% https://tex.stackexchange.com/a/673436
1112
\\usepackage{forest}
1213
\\forestset{
13-
*/.style={
14-
delay+={append={[]},}
15-
},
16-
rooted tree/.style={
17-
for tree={
18-
grow'=90,
19-
parent anchor=center,
20-
child anchor=center,
21-
s sep=2.5pt,
22-
if level=0{
23-
baseline
24-
}{},
25-
delay={
26-
if content={*}{
27-
content=,
28-
append={[]}
29-
}{}
14+
whitenode/.style={draw, circle, minimum size=0.5ex, inner sep=0pt},
15+
blacknode/.style={draw, fill=black, circle, minimum size=0.5ex, inner sep=0pt},
16+
colornode/.style={draw, fill=#1, circle, minimum size=0.5ex, inner sep=0pt},
17+
colornode/.default={red}
18+
}
19+
\\newcommand{\\blankforrootedtree}{\\rule{0pt}{0pt}}
20+
\\NewDocumentCommand\\rootedtree{o}{\\begin{forest}
21+
for tree={grow'=90, thick, edge=thick, l sep=0.5ex, l=0pt, s sep=0.5ex},
22+
delay={
23+
where content={}{
24+
for children={no edge, before drawing tree={for tree={y-=5pt}}}
3025
}
31-
},
32-
before typesetting nodes={
33-
for tree={
34-
circle,
35-
fill,
36-
minimum width=3pt,
37-
inner sep=0pt,
38-
child anchor=center,
39-
},
40-
},
41-
before computing xy={
42-
for tree={
43-
l=5pt,
26+
{
27+
where content={o}{content={\\blankforrootedtree}, whitenode}{
28+
where content={.}{content={\\blankforrootedtree}, blacknode}{}
29+
}
4430
}
4531
}
46-
}
47-
}
48-
\\DeclareDocumentCommand\\rootedtree{o}{\\Forest{rooted tree [#1]}}
32+
[#1]
33+
\\end{forest}}
34+
4935
```
5036
5137
# Examples
5238
5339
```jldoctest
5440
julia> rootedtree([1, 2, 2]) |> RootedTrees.latexify |> println
55-
\\rootedtree[[][]]
41+
\\rootedtree[.[.][.]]
5642
5743
julia> rootedtree([1, 2, 3, 3, 2]) |> RootedTrees.latexify |> println
58-
\\rootedtree[[[][]][]]
44+
\\rootedtree[.[.[.][.]][.]]
5945
```
6046
"""
6147
function latexify(t::RootedTree)
6248
if isempty(t)
6349
return "\\varnothing"
6450
end
6551
list_representation = butcher_representation(t, false)
66-
"\\rootedtree" * replace(list_representation, "τ" => "[]")
52+
s = "\\rootedtree" * replace(list_representation, "τ" => "[]")
53+
return replace(s, "[" => "[.")
54+
end
55+
56+
function latexify(t::BicoloredRootedTree)
57+
if isempty(t)
58+
return "\\varnothing"
59+
end
60+
list_representation = butcher_representation(rootedtree(t.level_sequence), false)
61+
s = "\\rootedtree" * replace(list_representation, "τ" => "[]")
62+
# The first entry of `substrings` is "\\rootedtree".
63+
substrings = split(s, "[")
64+
strings = String[]
65+
for (color, substring) in zip(t.color_sequence, substrings)
66+
if color == false
67+
push!(strings, substring * "[.")
68+
elseif color == true
69+
push!(strings, substring * "[o")
70+
end
71+
end
72+
# We still need to add the last part dropped by `zip`.
73+
push!(strings, last(substrings))
74+
return join(strings)
6775
end
6876

69-
Latexify.@latexrecipe function _(t::RootedTree)
77+
Latexify.@latexrecipe function _(t::Union{RootedTree, BicoloredRootedTree})
7078
return Latexify.LaTeXString(RootedTrees.latexify(t))
7179
end

test/runtests.jl

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ using Aqua: Aqua
151151
@test α(t1) == 1
152152
@test β(t1) == α(t1) * γ(t1)
153153
@test butcher_representation(t1) == "τ"
154-
latex_string = "\\rootedtree[]"
154+
latex_string = "\\rootedtree[.]"
155155
@test RootedTrees.latexify(t1) == latex_string
156156
@test latexify(t1) == latex_string
157157
@test isempty(RootedTrees.subtrees(t1))
@@ -173,7 +173,7 @@ using Aqua: Aqua
173173
@test β(t2) == α(t2) * γ(t2)
174174
@test t2 == t1 t1
175175
@test butcher_representation(t2) == "[τ]"
176-
latex_string = "\\rootedtree[[]]"
176+
latex_string = "\\rootedtree[.[.]]"
177177
@test RootedTrees.latexify(t2) == latex_string
178178
@test latexify(t2) == latex_string
179179
@test RootedTrees.subtrees(t2) == [rootedtree([2])]
@@ -186,7 +186,7 @@ using Aqua: Aqua
186186
@test β(t3) == α(t3) * γ(t3)
187187
@test t3 == t2 t1
188188
@test butcher_representation(t3) == "[τ²]"
189-
latex_string = "\\rootedtree[[][]]"
189+
latex_string = "\\rootedtree[.[.][.]]"
190190
@test RootedTrees.latexify(t3) == latex_string
191191
@test latexify(t3) == latex_string
192192
@test RootedTrees.subtrees(t3) == [rootedtree([2]), rootedtree([2])]
@@ -199,7 +199,7 @@ using Aqua: Aqua
199199
@test β(t4) == α(t4) * γ(t4)
200200
@test t4 == t1 t2
201201
@test butcher_representation(t4) == "[[τ]]"
202-
latex_string = "\\rootedtree[[[]]]"
202+
latex_string = "\\rootedtree[.[.[.]]]"
203203
@test RootedTrees.latexify(t4) == latex_string
204204
@test latexify(t4) == latex_string
205205
@test RootedTrees.subtrees(t4) == [rootedtree([2, 3])]
@@ -830,6 +830,49 @@ using Aqua: Aqua
830830
end
831831
end
832832

833+
@testset "latexify" begin
834+
let t = rootedtree(Int[], Bool[])
835+
latex_string = "\\varnothing"
836+
@test latexify(t) == latex_string
837+
end
838+
839+
let t = rootedtree([1], Bool[0])
840+
latex_string = "\\rootedtree[.]"
841+
@test latexify(t) == latex_string
842+
end
843+
844+
let t = rootedtree([1], Bool[1])
845+
latex_string = "\\rootedtree[o]"
846+
@test latexify(t) == latex_string
847+
end
848+
849+
let t = rootedtree([1, 2], Bool[0, 0])
850+
latex_string = "\\rootedtree[.[.]]"
851+
@test latexify(t) == latex_string
852+
end
853+
854+
let t = rootedtree([1, 2], Bool[1, 0])
855+
latex_string = "\\rootedtree[o[.]]"
856+
@test latexify(t) == latex_string
857+
end
858+
859+
let t = rootedtree([1, 2], Bool[0, 1])
860+
latex_string = "\\rootedtree[.[o]]"
861+
@test latexify(t) == latex_string
862+
end
863+
864+
let t = rootedtree([1, 2], Bool[1, 1])
865+
latex_string = "\\rootedtree[o[o]]"
866+
@test latexify(t) == latex_string
867+
end
868+
869+
let t = rootedtree([1, 2, 3, 4, 4, 3, 4, 3, 3, 2],
870+
Bool[0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
871+
latex_string = "\\rootedtree[.[o[.[o][.]][o[.]][o][.]][o]]"
872+
@test latexify(t) == latex_string
873+
end
874+
end
875+
833876
# see butcher2008numerical, Table 302(I)
834877
@testset "number of trees" begin
835878
number_of_rooted_trees = [1, 1, 1, 2, 4, 9, 20, 48, 115, 286, 719]

0 commit comments

Comments
 (0)