|
17 | 17 | REVERSE = -1 #: Direction constant for reverse tree traversal
|
18 | 18 | NODE_IS_SAMPLE = tskit.NODE_IS_SAMPLE
|
19 | 19 |
|
| 20 | +# We define these empty classes for documentation purposes only, |
| 21 | +# as the real classes are defined on demand once the size of allele |
| 22 | +# strings are known. |
| 23 | + |
| 24 | + |
| 25 | +class NumbaTreeSequence: |
| 26 | + """ |
| 27 | + A Numba-compatible representation of a tree sequence. |
| 28 | +
|
| 29 | + This class provides access a tree sequence class that can be used |
| 30 | + from within Numba "njit" compiled functions, as it is a Numba |
| 31 | + "jitclass". :meth:`numba_tree_sequence` should be used to |
| 32 | + create this class from a :class:`tskit.TreeSequence` object, |
| 33 | + before it is passed to a Numba function. |
| 34 | +
|
| 35 | + Attributes |
| 36 | + ---------- |
| 37 | + num_trees : int32 |
| 38 | + Number of trees in the tree sequence. |
| 39 | + num_nodes : int32 |
| 40 | + Number of nodes in the tree sequence. |
| 41 | + num_samples : int32 |
| 42 | + Number of samples in the tree sequence. |
| 43 | + num_edges : int32 |
| 44 | + Number of edges in the tree sequence. |
| 45 | + num_sites : int32 |
| 46 | + Number of sites in the tree sequence. |
| 47 | + num_mutations : int32 |
| 48 | + Number of mutations in the tree sequence. |
| 49 | + sequence_length : float64 |
| 50 | + Total sequence length of the tree sequence. |
| 51 | + edges_left : float64[] |
| 52 | + Left coordinates of edges. |
| 53 | + edges_right : float64[] |
| 54 | + Right coordinates of edges. |
| 55 | + edges_parent : int32[] |
| 56 | + Parent node IDs for each edge. |
| 57 | + edges_child : int32[] |
| 58 | + Child node IDs for each edge. |
| 59 | + nodes_time : float64[] |
| 60 | + Time values for each node. |
| 61 | + nodes_flags : uint32[] |
| 62 | + Flag values for each node. |
| 63 | + nodes_population : int32[] |
| 64 | + Population IDs for each node. |
| 65 | + nodes_individual : int32[] |
| 66 | + Individual IDs for each node. |
| 67 | + individuals_flags : uint32[] |
| 68 | + Flag values for each individual. |
| 69 | + sites_position : float64[] |
| 70 | + Positions of sites along the sequence. |
| 71 | + mutations_site : int32[] |
| 72 | + Site IDs for each mutation. |
| 73 | + mutations_node : int32[] |
| 74 | + Node IDs for each mutation. |
| 75 | + mutations_parent : int32[] |
| 76 | + Parent mutation IDs. |
| 77 | + mutations_time : float64[] |
| 78 | + Time values for each mutation. |
| 79 | + breakpoints : float64[] |
| 80 | + Genomic positions where trees change. |
| 81 | + indexes_edge_insertion_order : int32[] |
| 82 | + Order in which edges are inserted during tree building. |
| 83 | + indexes_edge_removal_order : int32[] |
| 84 | + Order in which edges are removed during tree building. |
| 85 | +
|
| 86 | + """ |
| 87 | + |
| 88 | + def tree_position(self): |
| 89 | + """ |
| 90 | + Create a :class:`NumbaTreePosition` for traversing this tree sequence. |
| 91 | +
|
| 92 | + Returns |
| 93 | + ------- |
| 94 | + NumbaTreePosition |
| 95 | + A new tree position initialized to the null tree. |
| 96 | + Use next() or prev() to move to actual tree positions. |
| 97 | +
|
| 98 | + Examples |
| 99 | + -------- |
| 100 | + >>> tree_pos = numba_ts.tree_position() |
| 101 | + >>> while tree_pos.next(): |
| 102 | + ... # Process current tree at tree_pos.index |
| 103 | + ... print(f"Tree {tree_pos.index}: {tree_pos.interval}") |
| 104 | + """ |
| 105 | + return NumbaTreePosition(self) |
| 106 | + |
| 107 | + def diversity(self): |
| 108 | + """ |
| 109 | + Calculate the genetic diversity of the tree sequence. |
| 110 | + Equivalent to the ts.diversity(mode="branch") |
| 111 | +
|
| 112 | + Returns |
| 113 | + ------- |
| 114 | + float |
| 115 | + Genetic diversity within the tree sequence. |
| 116 | + """ |
| 117 | + |
| 118 | + pass |
| 119 | + |
| 120 | +class NumbaTreePosition: |
| 121 | + """ |
| 122 | + Traverse trees in a numba compatible tree sequence. |
| 123 | +
|
| 124 | + This class provides efficient forward and backward iteration through |
| 125 | + the trees in a tree sequence. It tracks the current position and interval, |
| 126 | + providing edge changes between trees. |
| 127 | +
|
| 128 | +
|
| 129 | + Attributes |
| 130 | + ---------- |
| 131 | + ts : NumbaTreeSequence |
| 132 | + Reference to the tree sequence being traversed. |
| 133 | + index : int32 |
| 134 | + Current tree index. -1 indicates no current tree (null state). |
| 135 | + direction : int32 |
| 136 | + Traversal direction: tskit.FORWARD or tskit.REVERSE. tskit.NULL |
| 137 | + if uninitialised. |
| 138 | + interval : tuple of float64 |
| 139 | + Genomic interval (left, right) covered by the current tree. |
| 140 | + in_range : NumbaEdgeRange |
| 141 | + Edges being added to form this current tree, relative to the last state |
| 142 | + out_range : NumbaEdgeRange |
| 143 | + Edges being removed to form this current tree, relative to the last state |
| 144 | + site_range : tuple of int32 |
| 145 | + Range of sites in the current tree (start, stop). |
| 146 | + mutation_range : tuple of int32 |
| 147 | + Range of mutations in the current tree (start, stop). |
| 148 | +
|
| 149 | + Example |
| 150 | + -------- |
| 151 | + >>> tree_pos = numba_ts.tree_position() |
| 152 | + >>> num_edges |
| 153 | + >>> while tree_pos.next(): |
| 154 | + num_edges += (tree_pos.in_range.stop - tree_pos.in_range.start) |
| 155 | + num_edges -= (tree_pos.out_range.stop - tree_pos.out_range.start) |
| 156 | + print(f"Tree {tree_pos.index}: {num_edges} edges") |
| 157 | + """ |
| 158 | + |
| 159 | + def set_null(self): |
| 160 | + """ |
| 161 | + Reset the tree position to null state. |
| 162 | + """ |
| 163 | + pass |
| 164 | + |
| 165 | + def next(self): # noqa: A003 |
| 166 | + """ |
| 167 | + Move to the next tree in forward direction. |
| 168 | +
|
| 169 | + Updates the tree position to the next tree in the sequence, |
| 170 | + computing the edges that need to be added and removed to |
| 171 | + transform from the previous tree to the current tree, storing |
| 172 | + them in self.in_range and self.out_range. |
| 173 | +
|
| 174 | + Returns |
| 175 | + ------- |
| 176 | + bool |
| 177 | + True if successfully moved to next tree, False if the end |
| 178 | + of the tree sequence is reached. |
| 179 | + When False is returned, the iterator is in null state (index=-1). |
| 180 | +
|
| 181 | + Notes |
| 182 | + ----- |
| 183 | + On the first call, this initializes the iterator and moves to tree 0. |
| 184 | + The in_range and out_range attributes are updated to reflect the |
| 185 | + edge changes needed for the current tree. |
| 186 | + """ |
| 187 | + pass |
| 188 | + |
| 189 | + def prev(self): |
| 190 | + """ |
| 191 | + Move to the previous tree in reverse direction. |
| 192 | +
|
| 193 | + Updates the tree position to the previous tree in the sequence, |
| 194 | + computing the edges that need to be added and removed to |
| 195 | + transform from the next tree to the current tree, storing them |
| 196 | + in self.in_range and self.out_range |
| 197 | +
|
| 198 | + Returns |
| 199 | + ------- |
| 200 | + bool |
| 201 | + True if successfully moved to previous tree, False if the beginning |
| 202 | + of the tree sequence is reached. |
| 203 | + When False is returned, the iterator is in null state (index=-1). |
| 204 | +
|
| 205 | + Notes |
| 206 | + ----- |
| 207 | + On the first call, this initializes the iterator and moves to the most |
| 208 | + rightward tree. |
| 209 | + The in_range and out_range attributes are updated to reflect the |
| 210 | + edge changes needed for the current tree when traversing backward. |
| 211 | + """ |
| 212 | + pass |
| 213 | + |
20 | 214 | edge_range_spec = [
|
21 | 215 | ("start", numba.int32),
|
22 | 216 | ("stop", numba.int32),
|
|
0 commit comments