Tree.ancestors(u) method
As I've been implementing tree traversal methods, I've commonly wanted to go up the chain of parents for a node. I think there's a good argument for a tree.parents(u) (or tree.ancestors?) method which returns an iterator which then stops when the root is reached. This is a pretty fundamental tree operation and handy to avoid messing with all that tskit.NULL stuff for newbies:
def parents(self, u):
while self.parent(u) != tskit.NULL:
u = self.parent(u)
yield u
Thoughts? Worth the extra API burden?
We started implementing something similar in #2350, which was Tree.path(u, v=None) which returned the path to root when provided with a single node.
I think parents is a bit to easy to get mixed up with parent.
Tree.ancestors(u) is good choice I think, but we need to be careful with the implementation. This seems reasonable?
def ancestors(self, u):
"""
Returns an iterator over the ancestors of u in this tree.
"""
u = self.parent(u)
while u != -1:
yield u
u = self.parent(u)
Arguably it would be more useful/efficient to return a list or an array of the nodes, but I think it's probably best to be consistent with the nodes() function here by returning an iterator.
Similar function defined here