Skip to content

doc: book chapter on edge differences #417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [Initialization from a table collection](./tree_sequence_from_table_collection.md)
- [Iterating over trees](./tree_sequence_iterate_trees.md)
- [Working with trees](./tree_sequence_tree.md)
- [Edge differences](./tree_sequence_edge_diffs.md)
- [Miscellaneous operations](./tree_sequence_miscellaneous.md)

* [Metadata](./metadata.md)
Expand Down
19 changes: 19 additions & 0 deletions book/src/tree_sequence_edge_diffs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Iterating over edge differences

As with [trees](tree_sequence_iterate_trees.md), the API provides a *lending* iterator over edge differences.
Each step of the iterator advances to the next tree in the tree sequence.
For each tree, a standard `Iterator` over removals and insertions is available:

```rust, noplaygound, ignore
{{#include ../../tests/book_trees.rs:iterate_edge_differences}}
```

Edge differences are the basis of efficient algorithms based on the incremental updating of summaries of trees.
The following example co-iterates over edge differences and trees.
The edge differences are used to calculate the parent array for each tree:

```rust, noplaygound, ignore
{{#include ../../tests/book_trees.rs:iterate_edge_differences_update_parents}}
```


50 changes: 0 additions & 50 deletions src/trees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,56 +873,6 @@ pub(crate) mod test_trees {
panic!("Expected a tree.");
}
}

// TODO: use trybuild to add tests that the iterator
// lifetime is indeed coupled to that of the treeseq
#[test]
fn test_edge_diffs_lending_iterator_num_trees() {
{
let treeseq = treeseq_from_small_table_collection_two_trees();
let num_nodes: usize = treeseq.nodes().num_rows().try_into().unwrap();
let mut parents = vec![NodeId::NULL; num_nodes + 1];
if let Ok(mut ediff_iter) = treeseq.edge_differences_iter() {
let mut tree_iter = treeseq.tree_iterator(0).unwrap();
let mut ntrees = 0;
while let Some(diffs) = ediff_iter.next() {
let tree = tree_iter.next().unwrap();

for edge_out in diffs.edge_removals() {
let p = edge_out.child();
parents[usize::try_from(p).unwrap()] = NodeId::NULL;
}

for edge_in in diffs.edge_insertions() {
let c: usize = edge_in.child().try_into().unwrap();
parents[c] = edge_in.parent();
}

assert_eq!(tree.parent_array(), &parents);
ntrees += 1;
}
assert_eq!(ntrees, 2);
} else {
panic!("expected an edge differences iterator");
}
}

{
let treeseq = treeseq_from_small_table_collection_two_trees();
let mut ediff_iter = treeseq.edge_differences_iter().unwrap();

let mut ntrees = 0;
while let Some(diffs) = ediff_iter.next() {
if ntrees == 0 {
assert_eq!(diffs.interval(), (0.0.into(), 500.0.into()));
} else {
assert_eq!(diffs.interval(), (500.0.into(), 1000.0.into()));
}
ntrees += 1;
}
assert_eq!(ntrees, 2);
}
}
}

#[cfg(test)]
Expand Down
42 changes: 42 additions & 0 deletions tests/book_trees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,46 @@ fn initialize_from_table_collection() {
}
}
// ANCHOR_END: iterate_node_siblings_via_array_getters

// ANCHOR: iterate_edge_differences
if let Ok(mut edge_diff_iterator) = treeseq.edge_differences_iter() {
while let Some(diffs) = edge_diff_iterator.next() {
for edge_removal in diffs.edge_removals() {
println!("{}", edge_removal);
}
for edge_insertion in diffs.edge_insertions() {
println!("{}", edge_insertion);
}
}
} else {
panic!("creating edge diffs iterator failed");
}
// ANCHOR_END: iterate_edge_differences

// ANCHOR: iterate_edge_differences_update_parents
let num_nodes: usize = treeseq.nodes().num_rows().try_into().unwrap();
// num_nodes + 1 to reflect a "virtual root" present in
// the tree arrays
let mut parents = vec![NodeId::NULL; num_nodes + 1];
match treeseq.edge_differences_iter() {
Ok(mut ediff_iter) => match treeseq.tree_iterator(0) {
Ok(mut tree_iter) => {
while let Some(diffs) = ediff_iter.next() {
let tree = tree_iter.next().unwrap();
for edge_out in diffs.edge_removals() {
let c = edge_out.child();
parents[c.as_usize()] = NodeId::NULL;
}
for edge_in in diffs.edge_insertions() {
let c = edge_in.child();
parents[c.as_usize()] = edge_in.parent();
}
assert_eq!(tree.parent_array(), &parents);
}
}
Err(e) => panic!("error creating tree iter: {:?}", e),
},
Err(e) => panic!("error creating edge diff iter: {:?}", e),
}
// ANCHOR_END: iterate_edge_differences_update_parents
}