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
Copy file name to clipboardExpand all lines: docs/numba.md
+120-2Lines changed: 120 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,6 +44,8 @@ The numba integration provides:
44
44
-**{class}`NumbaTreeSequence`**: A Numba-compatible representation of tree sequence data
45
45
-**{class}`NumbaTreeIndex`**: A class for efficient tree iteration
46
46
-**{class}`NumbaEdgeRange`**: Container class for edge ranges during iteration
47
+
-**{class}`NumbaChildIndex`**: A class for efficiently finding child edges of nodes
48
+
-**{class}`NumbaParentIndex`**: A class for efficiently finding parent edges of nodes
47
49
48
50
These classes are designed to work within Numba's `@njit` decorated functions,
49
51
allowing you to write high-performance tree sequence analysis code.
@@ -76,7 +78,7 @@ print(type(numba_ts))
76
78
77
79
## Tree Iteration
78
80
79
-
Tree iteration can be performed using the {class}`NumbaTreeIndex` class.
81
+
Tree iteration can be performed in `numba.njit` compiled functions using the {class}`NumbaTreeIndex` class.
80
82
This class provides `next()` and `prev()` methods for forward and backward iteration through the trees in a tree sequence. Its `in_range` and `out_range` attributes provide the edges that must be added or removed to form the current
81
83
tree from the previous tree, along with the current tree `interval` and its sites and mutations through `site_range` and `mutation_range`.
Beyond iterating through trees, you may need to traverse the ARG vertically. The {class}`NumbaChildIndex` and {class}`NumbaParentIndex` classes provide efficient access to parent-child relationships in the edge table within `numba.njit` functions.
260
+
261
+
The {class}`NumbaChildIndex` allows you to efficiently find all edges where a given node is the parent. Since edges are already sorted by parent in the tskit data model, this is implemented using simple range indexing. For any node `u`, `child_range[u]` gives a tuple of the start and stop indices in the tskit edge table where node `u` is the parent.
262
+
263
+
The {class}`NumbaParentIndex` allows you to efficiently find all edges where a given node is the child. Since edges are not sorted by child in the edge table, this class builds a custom index that sorts edge IDs by child node (and then by left coordinate). For any node `u`, `parent_range[u]` gives a tuple of the start and stop indices in the `parent_index` array, and `parent_index[start:stop]` gives the actual tskit edge IDs.
264
+
265
+
Both indexes can be obtained from a `NumbaTreeSequence`:
266
+
267
+
```{code-cell} python
268
+
# Get the indexes
269
+
child_index = numba_ts.child_index()
270
+
parent_index = numba_ts.parent_index()
271
+
272
+
# Example: find all edges where node 5 is the parent
273
+
start, stop = child_index.child_range[5]
274
+
print(f"Node 5 has {stop - start} child edges")
275
+
276
+
# Example: find all edges where node 3 is the child
277
+
start, stop = parent_index.parent_range[3]
278
+
print(f"Node 3 appears as child in {stop - start} edges")
279
+
```
280
+
281
+
These indexes enable efficient algorithms that need to traverse parent-child relationships in the ARG, such as computing descendant sets, ancestral paths, or subtree properties.
282
+
283
+
### Example - descendant span calculation
284
+
285
+
Here's an example of using the ARG traversal classes to calculate the total sequence length over which each node descends from a specified node:
286
+
287
+
```{code-cell} python
288
+
@numba.njit
289
+
def descendant_span(numba_ts, u):
290
+
"""
291
+
Calculate the total sequence length over which each node
292
+
descends from the specified node u.
293
+
"""
294
+
child_index = numba_ts.child_index()
295
+
child_range = child_index.child_range
296
+
edges_left = numba_ts.edges_left
297
+
edges_right = numba_ts.edges_right
298
+
edges_child = numba_ts.edges_child
299
+
300
+
total_descending = np.zeros(numba_ts.num_nodes)
301
+
stack = [(u, 0.0, numba_ts.sequence_length)]
302
+
303
+
# TODO is it right that u is considered to inherit from itself
304
+
# across the whole sequence?
305
+
total_descending[u] = numba_ts.sequence_length
306
+
307
+
while len(stack) > 0:
308
+
node, left, right = stack.pop()
309
+
310
+
# Find all child edges for this node
311
+
for e in range(child_range[node, 0], child_range[node, 1]):
0 commit comments