Skip to content

Commit ec6d3f6

Browse files
authored
doc: book section on the tree API. (#382)
1 parent 1f0d8c8 commit ec6d3f6

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
- [Working with tree sequences](./working_with_tree_sequences.md)
1313
- [Initialization from a table collection](./tree_sequence_from_table_collection.md)
1414
- [Iterating over trees](./tree_sequence_iterate_trees.md)
15+
- [Working with trees](./tree_sequence_tree.md)

book/src/tree_sequence_tree.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Working with trees
2+
3+
Iterating over a tree sequence returns instances of `tskit::Tree`.
4+
This type is immutable.
5+
No access is provided to the underlying pointers.
6+
7+
The API provides a set of iterators over the data in a tree.
8+
9+
For example, to collect the siblings of each node into a vector:
10+
11+
```rust, noplaygound, ignore
12+
{{#include ../../tests/book_trees.rs:iterate_node_siblings}}
13+
```
14+
15+
We may do the same calculation using API elements giving `&[NodeId]`
16+
(slices of node ids).
17+
This method more closely matches the `tskit-c` API.
18+
19+
```rust, noplaygound, ignore
20+
{{#include ../../tests/book_trees.rs:iterate_node_siblings_via_arrays}}
21+
```
22+
23+
This approach is more complex:
24+
25+
* Slice element access is via `usize` (`size_t` in C/C++).
26+
* Row ids are `i32` (`tsk_id_t` in `tskit-c`) behind the newtypes.
27+
* `tskit` implements `TryFrom` to help you out, forcing
28+
you to reckon with the fact that conversion from `i32`
29+
to `usize` is fallible.
30+
31+
These conversion semantics require us to manually handle all possible error
32+
paths at each step.
33+
34+
We can have an intermediate level of complexity using getters from the tree arrays:
35+
36+
```rust, noplaygound, ignore
37+
{{#include ../../tests/book_trees.rs:iterate_node_siblings_via_array_getters}}
38+
```

tests/book_trees.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,77 @@ fn initialize_from_table_collection() {
7373
// _tree is a tskit::Tree
7474
}
7575
// ANCHOR_END: iterate_trees
76+
77+
let mut tree_iterator = treeseq.tree_iterator(TreeFlags::default()).unwrap();
78+
// ANCHOR: iterate_node_siblings
79+
// This is an enum defining supported
80+
// traversal orders through a Tree.
81+
use tskit::NodeTraversalOrder;
82+
while let Some(tree) = tree_iterator.next() {
83+
for node in tree.traverse_nodes(NodeTraversalOrder::Preorder) {
84+
if let Some(parent) = tree.parent(node) {
85+
// Collect the siblings of node into a Vec
86+
// The children function returns another iterator
87+
let _siblings = if let Some(child_iterator) = tree.children(parent) {
88+
child_iterator
89+
.filter(|child| child != &node)
90+
.collect::<Vec<_>>()
91+
} else {
92+
// assign empty vector
93+
vec![]
94+
};
95+
}
96+
}
97+
}
98+
// ANCHOR_END: iterate_node_siblings
99+
100+
let mut tree_iterator = treeseq.tree_iterator(TreeFlags::default()).unwrap();
101+
// ANCHOR: iterate_node_siblings_via_arrays
102+
while let Some(tree) = tree_iterator.next() {
103+
let parents = tree.parent_array();
104+
let rsibs = tree.right_sib_array();
105+
let lchildren = tree.left_child_array();
106+
for node in tree.traverse_nodes(NodeTraversalOrder::Preorder) {
107+
let mut siblings = vec![];
108+
assert!(!node.is_null());
109+
if let Some(parent) = parents.get(usize::try_from(node).unwrap()) {
110+
if !parent.is_null() {
111+
if let Some(child) = lchildren.get(usize::try_from(*parent).unwrap()) {
112+
let mut u = *child;
113+
while !u.is_null() {
114+
if u != node {
115+
siblings.push(u);
116+
}
117+
if let Some(sib) = rsibs.get(usize::try_from(u).unwrap()) {
118+
u = *sib;
119+
}
120+
}
121+
}
122+
}
123+
}
124+
}
125+
}
126+
// ANCHOR_END: iterate_node_siblings_via_arrays
127+
128+
let mut tree_iterator = treeseq.tree_iterator(TreeFlags::default()).unwrap();
129+
// ANCHOR: iterate_node_siblings_via_array_getters
130+
while let Some(tree) = tree_iterator.next() {
131+
for node in tree.traverse_nodes(NodeTraversalOrder::Preorder) {
132+
let mut siblings = vec![];
133+
if let Some(parent) = tree.parent(node) {
134+
if let Some(child) = tree.left_child(parent) {
135+
let mut u = child;
136+
while !u.is_null() {
137+
if u != node {
138+
siblings.push(u);
139+
}
140+
if let Some(sib) = tree.right_sib(u) {
141+
u = sib;
142+
}
143+
}
144+
}
145+
}
146+
}
147+
}
148+
// ANCHOR_END: iterate_node_siblings_via_array_getters
76149
}

0 commit comments

Comments
 (0)