Directed Generator#
The phylozoo.core.network.dnetwork.generator module provides the DirectedGenerator
class and related functions for working with directed level-k generators (sometimes also referred to as “rooted level-k generators”).
All classes and functions on this page can be imported from the directed generator module:
from phylozoo.core.network.dnetwork.generator import *
# or directly
from phylozoo.core.network.dnetwork.generator import DirectedGenerator
What is a (directed) generator?#
A directed generator is a fundamental building block of a binary directed phylogenetic network. Formally, it is a directed multi-graph that can be obtained from a blob of a directed network by suppressing all vertices with degree 2 except those with indegree 2. Equivalently, a directed generator can be obtained from a simple directed network (i.e., a network consisting of a single internal blob) by removing all leaves and thereafter suppressing all vertices with degree 2 except those with indegree 2. See, for example, [Gambette et al., 2009] for more details.
Working with generators#
Creating a generator#
You can obtain a directed generator in two ways.
From a graph
Build a generator from a DirectedMultiGraph
that represents the generator topology. A level-0 generator is a single node with no edges. A level-1 generator is a root
node with two parallel directed edges to one hybrid node.
from phylozoo.core.network.dnetwork.generator import DirectedGenerator
from phylozoo.core.primitives.d_multigraph import DirectedMultiGraph
# Level-1 generator (root with two parallel edges to hybrid node)
gen_graph = DirectedMultiGraph(edges=[(8, 4), (8, 4)])
generator = DirectedGenerator(gen_graph)
# Level-0 generator (single node, no edges)
gen_graph0 = DirectedMultiGraph()
gen_graph0.add_node(1)
generator0 = DirectedGenerator(gen_graph0)
From a network
Alternatively, you can extract all generators from a directed network using the generators_from_network() function.
from phylozoo.core.network.dnetwork.generator import generators_from_network
from phylozoo import DirectedPhyNetwork
network = DirectedPhyNetwork.load("network.enewick")
generators = list(generators_from_network(network))
for gen in generators:
print(f"Level: {gen.level}, Hybrid nodes: {gen.hybrid_nodes}")
Note
Upon construction, a generator is validated using validate() to ensure it has a valid structure that adheres to the definition of a directed generator.
For details on PhyloZoo’s validation system and how to disable it for performance reasons, see
Validation.
Accessing generator attributes#
The underlying graph, root node, level, and hybrid nodes of a generator can be accessed as follows. The hybrid nodes are the nodes with indegree 2; the level is the number of hybrid nodes; the root node is the node with in-degree 0.
graph = generator.graph
root = generator.root_node
level = generator.level
hybrid_nodes = generator.hybrid_nodes
Sides of a generator#
The sides of a generator are precisely the points where leaves can be attached to create a directed network. The module provides the following types of side types.
Base classes
Side— The base class from which all other side types inherit.NodeSideis the base class for node attachment.EdgeSideis the base class for edge attachment.
Node sides
HybridSide— A hybrid node (in-degree ≥ 2) with out-degree 0 that serves as an attachment point.IsolatedNodeSide— The single vertex of a level-0 generator. Exactly one such side exists when level is 0.
Edge sides
DirEdgeSide— A directed edge (possibly one of several parallel edges), identified byu,v, andkey.
The sides of a generator can be accessed as follows:
from phylozoo.core.network.dnetwork.generator import (
HybridSide, DirEdgeSide, IsolatedNodeSide,
)
hybrid_side = HybridSide(node=3)
edge_side = DirEdgeSide(u=8, v=4, key=0)
# generator.sides: level-0 → [IsolatedNodeSide(root)]; level≥1 → edge_sides + hybrid_sides
all_sides = generator.sides
hybrid_sides = generator.hybrid_sides
edge_sides = generator.edge_sides
parallel_sides = generator.parallel_edge_sides
non_parallel_sides = generator.non_parallel_edge_sides
for side in generator.sides:
if isinstance(side, HybridSide):
print(f"Hybrid side at node: {side.node}")
elif isinstance(side, DirEdgeSide):
print(f"Edge side: ({side.u}, {side.v}, key={side.key})")
elif isinstance(side, IsolatedNodeSide):
print(f"Isolated node side: {side.node}")
Attaching leaves to a generator#
attach_leaves_to_generator() takes a
generator and a mapping side_taxa from sides to ordered lists of taxon labels, and returns a
DirectedPhyNetwork by attaching new leaf nodes to
the generator’s graph.
Rules
Every
HybridSidemust appear inside_taxawith exactly one taxon.Every
IsolatedNodeSide(level-0 only) must appear inside_taxawith exactly three taxa.DirEdgeSidesides may be omitted or given an empty list; they then receive no leaves. Note that the order of the taxa on the sides is important.At least two taxa must be attached in total across all sides.
from phylozoo.core.network.dnetwork.generator import (
DirectedGenerator, attach_leaves_to_generator,
)
from phylozoo.core.primitives.d_multigraph import DirectedMultiGraph
dmg = DirectedMultiGraph(edges=[(0, 1), (0, 1)])
gen = DirectedGenerator(dmg)
hybrid_side = gen.hybrid_sides[0]
edge_side = gen.edge_sides[0]
network = attach_leaves_to_generator(
gen, {hybrid_side: ["H"], edge_side: ["A", "B"]}
)
sorted(network.taxa)
# ['A', 'B', 'H']
Enumerating all generators#
The function all_level_k_generators() generates
all distinct level-k directed generators (up to isomorphism), using the algorithm described in [Gambette et al., 2009]. It starts with level-0 (single node),
then iteratively applies two extension rules (R1 and R2) to level-(k-1) generators and
deduplicates by isomorphism.
from phylozoo.core.network.dnetwork.generator import all_level_k_generators
level_0 = all_level_k_generators(0) # 1 generator
level_1 = all_level_k_generators(1) # 1 generator
level_2 = all_level_k_generators(2) # 4 generators
See Also#
Directed Network Class - The DirectedPhyNetwork class
Semi-Directed Network Generators - Semi-directed generators
Validation - Validation system and disabling validation
API Reference - Complete function signatures and detailed examples