Skip to content

Commit fbdabe4

Browse files
committed
Add preorder node traversal using latest tskit C API.
Closes #177 Fix preorder stack population for when root changes within a tree. Fixes #187
1 parent db8550f commit fbdabe4

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

src/trees.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ impl Tree {
497497
) -> Box<dyn Iterator<Item = NodeId> + '_> {
498498
match order {
499499
NodeTraversalOrder::Preorder => Box::new(PreorderNodeIterator::new(self)),
500+
NodeTraversalOrder::Postorder => Box::new(PostorderNodeIterator::new(self)),
500501
}
501502
}
502503

@@ -621,6 +622,10 @@ pub enum NodeTraversalOrder {
621622
///For trees with multiple roots, start at the left root,
622623
///traverse to tips, proceeed to the next root, etc..
623624
Preorder,
625+
///Postorder traversal, starting at the root(s) of a [`Tree`].
626+
///For trees with multiple roots, start at the left root,
627+
///traverse to tips, proceeed to the next root, etc..
628+
Postorder,
624629
}
625630

626631
struct PreorderNodeIterator<'a> {
@@ -663,6 +668,11 @@ impl NodeIterator for PreorderNodeIterator<'_> {
663668
None => {
664669
if let Some(r) = self.root_stack.pop() {
665670
self.current_node_ = Some(r);
671+
let mut c = self.tree.right_child(r).unwrap();
672+
while c != NodeId::NULL {
673+
self.node_stack.push(c);
674+
c = self.tree.left_sib(c).unwrap();
675+
}
666676
}
667677
}
668678
};
@@ -675,6 +685,64 @@ impl NodeIterator for PreorderNodeIterator<'_> {
675685

676686
iterator_for_nodeiterator!(PreorderNodeIterator<'_>);
677687

688+
struct PostorderNodeIterator<'a> {
689+
nodes: Vec<NodeId>,
690+
current_node_index: usize,
691+
num_nodes_current_tree: usize,
692+
// Make the lifetime checker happy.
693+
tree: std::marker::PhantomData<&'a Tree>,
694+
}
695+
696+
impl<'a> PostorderNodeIterator<'a> {
697+
fn new(tree: &'a Tree) -> Self {
698+
let mut num_nodes_current_tree: usize = 0;
699+
let ptr = std::ptr::addr_of_mut!(num_nodes_current_tree);
700+
let mut nodes = vec![
701+
NodeId::NULL;
702+
// NOTE: this fn does not return error codes
703+
unsafe { ll_bindings::tsk_tree_get_size_bound(tree.inner) } as usize
704+
];
705+
706+
let rv = unsafe {
707+
ll_bindings::tsk_tree_postorder(
708+
tree.inner,
709+
NodeId::NULL.into(), // start from virtual root
710+
nodes.as_mut_ptr() as *mut tsk_id_t,
711+
ptr as *mut tsk_size_t,
712+
)
713+
};
714+
715+
// This is either out of memory
716+
// or node out of range.
717+
// The former is fatal, and the latter
718+
// not relevant (for now), as we start at roots.
719+
if rv < 0 {
720+
panic!("fatal error calculating postoder node list");
721+
}
722+
723+
Self {
724+
nodes,
725+
current_node_index: 0,
726+
num_nodes_current_tree,
727+
tree: std::marker::PhantomData,
728+
}
729+
}
730+
}
731+
732+
impl<'a> Iterator for PostorderNodeIterator<'a> {
733+
type Item = NodeId;
734+
fn next(&mut self) -> Option<Self::Item> {
735+
match self.current_node_index < self.num_nodes_current_tree {
736+
true => {
737+
let rv = self.nodes[self.current_node_index];
738+
self.current_node_index += 1;
739+
Some(rv)
740+
}
741+
false => None,
742+
}
743+
}
744+
}
745+
678746
struct RootIterator<'a> {
679747
current_root: Option<NodeId>,
680748
next_root: NodeId,
@@ -1320,14 +1388,50 @@ pub(crate) mod test_trees {
13201388
assert_eq!(treeseq.num_trees(), 2);
13211389
let mut tree_iter = treeseq.tree_iterator(TreeFlags::SAMPLE_LISTS).unwrap();
13221390
while let Some(tree) = tree_iter.next() {
1391+
let mut preoder_nodes = vec![];
1392+
let mut postoder_nodes = vec![];
13231393
for n in tree.traverse_nodes(NodeTraversalOrder::Preorder) {
13241394
let mut nsamples = 0;
1395+
preoder_nodes.push(n);
13251396
for _ in tree.samples(n).unwrap() {
13261397
nsamples += 1;
13271398
}
13281399
assert!(nsamples > 0);
13291400
assert_eq!(nsamples, tree.num_tracked_samples(n).unwrap());
13301401
}
1402+
for n in tree.traverse_nodes(NodeTraversalOrder::Postorder) {
1403+
let mut nsamples = 0;
1404+
postoder_nodes.push(n);
1405+
for _ in tree.samples(n).unwrap() {
1406+
nsamples += 1;
1407+
}
1408+
assert!(nsamples > 0);
1409+
assert_eq!(nsamples, tree.num_tracked_samples(n).unwrap());
1410+
}
1411+
assert_eq!(preoder_nodes.len(), postoder_nodes.len());
1412+
1413+
// Test our preorder against the tskit functions in 0.99.15
1414+
{
1415+
let mut nodes: Vec<NodeId> = vec![
1416+
NodeId::NULL;
1417+
unsafe { ll_bindings::tsk_tree_get_size_bound(tree.as_ptr()) }
1418+
as usize
1419+
];
1420+
let mut num_nodes: tsk_size_t = 0;
1421+
let ptr = std::ptr::addr_of_mut!(num_nodes);
1422+
unsafe {
1423+
ll_bindings::tsk_tree_preorder(
1424+
tree.as_ptr(),
1425+
-1,
1426+
nodes.as_mut_ptr() as *mut tsk_id_t,
1427+
ptr,
1428+
);
1429+
}
1430+
assert_eq!(num_nodes as usize, preoder_nodes.len());
1431+
for i in 0..num_nodes as usize {
1432+
assert_eq!(preoder_nodes[i], nodes[i]);
1433+
}
1434+
}
13311435
}
13321436
}
13331437

0 commit comments

Comments
 (0)