treeflow.tree.topology.numpy_tree_topology module
- class treeflow.tree.topology.numpy_tree_topology.NumpyTreeTopology(parent_indices: ndarray, taxon_set: TaxonSet | None = None)
Bases:
NumpyTreeTopologyAttrsClass representing a bifurcating tree topology as a composition of integer NumPy arrays.
For a phylogenetic tree with
ntaxa at the leaves, the representation maintains a labelling of the1n-1nodes with integer indices. The labelling convention is that the leaves are the firstnindices and the root is at the last index (2n-2).- property taxon_count: int
Number of leaf taxa the tree is based on (
n)
- property node_count: int
- property postorder_node_indices: ndarray
- property child_indices: ndarray
Array of length
2n-2representing the parent-child structure of a tree topology onntaxa.The
ith element of this array is the index of the parent of theith indexed node in the tree, for every node except the root.
- property preorder_indices: ndarray
Array of indices of length
2n-1that form a pre-order traversal of the tree.A pre-order traversal is an ordering of the nodes where every node is visited before its children, starting at the root.
- parent_indices: ndarray
- class treeflow.tree.topology.numpy_tree_topology.StaticNumpyTreeTopology(parent_indices: ndarray, taxon_set: TaxonSet | None = None)
Bases:
objectA
NumpyTreeTopologyvariant with every derived index array pre-computed at construction.NumpyTreeTopologyis anattrsclass, whichtf.nestexpands into its singleparent_indicesleaf. Passing one into atf.functiontherefore replacesparent_indiceswith a symbolic placeholder, and the lazily-computed NumPy properties (child_indicesetc.) then fail on the symbolic tensor.This class is a plain Python object instead, so
tf.nesttreats it as an atom: it threads through traced code as a captured constant, and its index arrays stay concrete NumPy arrays inside the trace. That letstf.get_static_valuefold the topology regardless of tree size, so the node-height ratio-transform traversal unrolls rather than falling back to atf.while_loop.It is meant to be used as a fixed-topology pin. It is not a Tensor, so it is not placed directly into a JointDistribution’s tree value (which TFP coerces to tensors);
FixedTopologyRootedTreeBijectorrebuilds it as an in-graph-constantTensorflowTreeTopologyfor that purpose (see its_forward).- classmethod from_numpy_topology(topology: NumpyTreeTopology) StaticNumpyTreeTopology
- property parent_indices: ndarray
- property child_indices: ndarray
- property preorder_indices: ndarray
- property taxon_count: int
- property node_count: int
- property postorder_node_indices: ndarray
- property node_child_indices: ndarray
- property preorder_node_indices: ndarray
- has_batch_dimensions() bool
- to_constant_tensor_topology()
Return a
TensorflowTreeTopologywhose index arrays are ``tf.constant``s.IMPORTANT: call this inside a
tf.functiontrace (e.g. a VI loss step, the fixed-topology bijector’sforward, or a profiler timing function). The arrays then become in-graphConstops, which gives both properties we need at once:a normal tensor topology that a
JointDistributionaccepts in its tree value (it coerces the value to tensors), anda topology that still folds via
tf.get_static_valueat any tree size, so the downstream traversals unroll.
Calling it eagerly and capturing the result into a later trace loses the second property: a captured constant can be re-materialised as a
Placeholderfor large trees (the >64-taxon non-fold), which is exactly what building theConstinside the trace avoids.
- numpy() NumpyTreeTopology