You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tutorial on edge_diffs / incremental algorithms #233
There's a lot of idioms and complicated code when implementing incremental algorithms, for example, that use the edge_diffs() iterator. For example it's a common idiom to iterate jointly over trees and edges diffs:
When going through the edge diffs, it is also often useful to keep track of which nodes come in and out of the tree (and hence maintain a list of "active" nodes). For example, I think this is what I need for tskit-dev/tskit#2718. I've done this sort of thing before, but forgotten the code that I used to do it. A tutorial might be a good place to put example code for people to modify. I assume it would be linked to from the "Fundamental operations" tute mentioned in #203
Ah yes, I remember, this sort of tallying of nodes when passing over edge_diffs (and in this case, counting sample numbers under them), was what I did when implementing the spans_by_samples function in tsdate.
A good example for a simple incremental algorithm is to keep track of the number of descendants of every node in the trees:
importnumpyasnpimporttskitts= ...
# Subtree size including the node itself.num_descendants=np.ones(ts.num_nodes, dtype=ts.edges_child.dtype)
# Can't use tree.parent_array as we need this for the previous and this treeparent=np.full( ts.num_nodes, tskit.NULL, dtype=ts.edges_child.dtype)
defupdate_ancestors(total_nodes, parent, u, delta):
whileu!=tskit.NULL:
total_nodes[u] +=deltau=parent[u]
forinterval, edges_out, edges_inints.edge_diffs():
# edge_diffs() ordering guarantees that total_nodes[e.child]# is already correct when each edge is processed, i.e.# edges_out: descending parent time (i.e. postorder)# edges_in: ascending parent time (i.e. preorder)# so whole child subtrees can be moved as a single block.foreinedges_out:
delta=-num_descendants[e.child]
update_ancestors(num_descendants, parent, e.parent, delta)
parent[e.child] =tskit.NULLforeinedges_in:
parent[e.child] =e.parentdelta=num_descendants[e.child]
update_ancestors(num_descendants, parent, e.parent, delta)
This can be compared against calculating the num_descendants every time, e.g. via tskit-dev/tskit#2525
Activity
hyanwong commentedon Mar 1, 2023
Ah yes, I remember, this sort of tallying of nodes when passing over edge_diffs (and in this case, counting sample numbers under them), was what I did when implementing the spans_by_samples function in
tsdate.hyanwong commentedon May 28, 2026
A good example for a simple incremental algorithm is to keep track of the number of descendants of every node in the trees:
This can be compared against calculating the num_descendants every time, e.g. via tskit-dev/tskit#2525