triplet#

Triplet module.

This module provides classes for representing and working with triplets, which are rooted trees on 3 taxa. A triplet can either be resolved (with a single trivial 1|2 split a|bc, where a is a child of the root and b, c form a cherry under an internal node) or unresolved (a star tree where the root has three direct leaf children). The public API (Triplet, TripletProfile, TripletProfileSet) is re-exported here; the implementation is split across the base, tprofile, and tprofileset submodules.

Main Classes#

Triplet base module.

This module provides the Triplet class for representing triplets (3-taxon rooted trees). A triplet can be resolved (single trivial 1|2 split, where the singleton side is a direct child of the root and the 2-element side forms a cherry below an internal node) or unresolved (star tree, where the root has three direct leaf children).

class phylozoo.core.triplet.base.Triplet(split: Split | frozenset[str] | set[str])[source]#

Bases: object

Immutable triplet datatype representing a rooted tree on 3 taxa.

A triplet can either have a single trivial 1|2 split representing a resolved rooted tree (the singleton side is a direct child of the root and the 2-element side forms a cherry under an internal node), or be a star tree (represented by a set of 3 taxa) where the root has three direct leaf children.

Parameters:

split (Split | frozenset[str] | set[str]) – Either a trivial 1|2 split on 3 taxa, or a set/frozenset of exactly 3 taxon labels for a star tree.

Raises:

PhyloZooValueError – If not exactly 3 taxa, or if split is not trivial (not 1|2).

Examples

>>> from phylozoo.core.split.base import Split
>>> triplet = Triplet(Split({1}, {2, 3}))
>>> triplet.taxa
frozenset({1, 2, 3})
>>> triplet.is_resolved()
True
>>> star_triplet = Triplet({1, 2, 3})
>>> star_triplet.is_star()
True
__eq__(other: object) bool[source]#

Check if two triplets are equal.

Parameters:

other (object) – Object to compare with.

Returns:

True if triplets have same taxa and split, False otherwise.

Return type:

bool

__hash__() int[source]#

Return hash of the triplet.

Returns:

Hash value.

Return type:

int

__repr__() str[source]#

Return string representation of the triplet.

Returns:

String representation.

Return type:

str

__setattr__(name: str, value: object) None[source]#

Prevent modification of attributes after initialization.

Raises:

AttributeError – If attempting to modify any attribute after initialization.

__str__() str[source]#

Return human-readable string representation of the triplet.

For resolved triplets, displays as “Triplet(a | b c)” where a is the outgroup and b, c are the cherry leaves. For unresolved (star) triplets, displays as “Triplet(a b c)”.

Returns:

Human-readable string representation.

Return type:

str

Examples

>>> from phylozoo.core.split.base import Split
>>> triplet = Triplet(Split({1}, {2, 3}))
>>> str(triplet)
'Triplet(1 | 2 3)'
>>> star_triplet = Triplet({1, 2, 3})
>>> str(star_triplet)
'Triplet(1 2 3)'
property cherry: frozenset[str] | None#

Get the cherry of the triplet (2-element side of the split).

For a resolved triplet a|{b,c}, returns frozenset({b, c}) – the two taxa that share an internal parent below the root. For a star tree there is no cherry and None is returned.

Returns:

The 2-element side of the split, or None for star tree.

Return type:

frozenset[str] | None

copy() Triplet[source]#

Create a copy of the triplet.

Returns:

A new Triplet instance with the same taxa and split.

Return type:

Triplet

is_resolved() bool[source]#

Check if the triplet is resolved (has a trivial split).

Returns:

True if the triplet has a split (is resolved), False if it’s a star tree.

Return type:

bool

is_star() bool[source]#

Check if the triplet is a star tree (no split).

Returns:

True if the triplet is a star tree, False if it’s resolved.

Return type:

bool

property outgroup: frozenset[str] | None#

Get the outgroup of the triplet (singleton side of the split).

For a resolved triplet a|{b,c}, returns frozenset({a}) – the single taxon that is a direct child of the root. For a star tree there is no outgroup and None is returned.

Returns:

The singleton side of the split, or None for star tree.

Return type:

frozenset[str] | None

property split: Split | None#

Get the split of the triplet.

Returns:

The split representing the topology, or None for star tree.

Return type:

Split | None

property taxa: frozenset[str]#

Get the taxa of the triplet.

Returns:

The 3 taxon labels.

Return type:

frozenset[str]

to_network() DirectedPhyNetwork[source]#

Convert the triplet to a DirectedPhyNetwork.

For a resolved triplet a|{b,c}, creates a rooted binary tree with a root node (with the outgroup a as one child and an internal node as the other child) and an internal node whose two children are the cherry leaves b and c. For a star tree, creates a rooted tree with all three taxa as direct children of the root.

Returns:

A directed phylogenetic network representing the rooted triplet topology.

Return type:

DirectedPhyNetwork

Triplet profile module.

A triplet profile groups multiple triplets on the same 3-taxon set, each with an associated weight representing the relative importance or frequency of each triplet topology. This module provides the TripletProfile class; total weight is always 1.0.

class phylozoo.core.triplet.tprofile.TripletProfile(triplets: dict[Triplet, float] | Mapping[Triplet, float] | list[Triplet] | list[tuple[Triplet, float]])[source]#

Bases: object

Immutable profile for triplets on the same 3-taxon set.

A TripletProfile groups multiple triplets that share the same 3 taxa, each with an associated weight. The weights always sum to 1.0 (within a small tolerance), so the profile represents a probability distribution over triplet topologies.

  • If no weights are provided (list of triplets), each triplet is assigned equal weight 1/k, where k is the number of triplets.

  • If weights are provided (dict or list of (triplet, weight) tuples), they must sum to 1.0 (within tolerance); they are not scaled.

Parameters:

triplets (dict[Triplet, float] | Mapping[Triplet, float] | list[Triplet] | list[tuple[Triplet, float]]) –

Input triplets. Can be:

  • A dictionary mapping triplets to weights (must sum to 1.0)

  • A list of triplets (each assigned weight 1/k)

  • A list of (triplet, weight) tuples (weights must sum to 1.0)

Taxa are automatically extracted from the triplets.

Raises:

PhyloZooValueError – If triplets is empty, if triplets have different taxa, if any weight is non-positive, or if provided weights do not sum to 1.0.

Examples

>>> from phylozoo.core.split.base import Split
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> # From dictionary with weights (already sum to 1.0)
>>> profile = TripletProfile({t1: 0.8, t2: 0.2})
>>> profile.taxa
frozenset({1, 2, 3})
>>> profile.get_weight(t1)
0.8
>>> # From list of triplets (equal weight 1/k each)
>>> profile2 = TripletProfile([t1, t2])
>>> profile2.get_weight(t1)
0.5
>>> profile2.get_weight(t2)
0.5
__contains__(triplet: Triplet) bool[source]#

Check if a triplet is in the profile.

Parameters:

triplet (Triplet) – Triplet to check.

Returns:

True if the triplet is in the profile, False otherwise.

Return type:

bool

__iter__() Iterator[Triplet][source]#

Return an iterator over the triplets.

Returns:

Iterator over triplets.

Return type:

Iterator[Triplet]

__len__() int[source]#

Return the number of triplets in the profile.

Returns:

Number of triplets.

Return type:

int

__repr__() str[source]#

Return string representation of the profile.

Returns:

String representation.

Return type:

str

__setattr__(name: str, value: object) None[source]#

Prevent modification of attributes after initialization.

Raises:

AttributeError – If attempting to modify any attribute after initialization.

__str__() str[source]#

Return human-readable string representation of the triplet profile.

Displays one line per triplet, showing the triplet (using its __str__ method) and its weight.

Returns:

Human-readable string representation.

Return type:

str

Examples

>>> from phylozoo.core.split.base import Split
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> profile = TripletProfile({t1: 0.8, t2: 0.2})
>>> str(profile)
'TripletProfile({\n  Triplet(1 | 2 3): 0.8,\n  Triplet(2 | 1 3): 0.2\n})'
get_weight(triplet: Triplet) float[source]#

Get the weight of a triplet.

Parameters:

triplet (Triplet) – The triplet to get the weight for.

Returns:

The weight of the triplet, or 0.0 if not found.

Return type:

float

is_resolved() bool[source]#

Check if the profile is resolved.

A profile is resolved if all its triplets are resolved. A triplet is resolved if it has a trivial split (i.e., it’s not a star tree).

Returns:

True if all triplets are resolved (profile is resolved), False otherwise.

Return type:

bool

Examples

>>> from phylozoo.core.split.base import Split
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> profile = TripletProfile([t1, t2])
>>> profile.is_resolved()
True
>>> t3 = Triplet({1, 2, 3})  # Star tree
>>> profile2 = TripletProfile([t1, t3])
>>> profile2.is_resolved()
False
is_trivial() bool[source]#

Check if the profile is trivial (contains exactly one triplet).

A trivial profile is essentially a single triplet, meaning it represents a single topology rather than a distribution over multiple topologies.

Returns:

True if the profile contains exactly one triplet, False otherwise.

Return type:

bool

Examples

>>> from phylozoo.core.split.base import Split
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> profile = TripletProfile([t1])
>>> profile.is_trivial()
True
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> profile2 = TripletProfile({t1: 0.8, t2: 0.2})
>>> profile2.is_trivial()
False
property split: Split | None#

Get the split if the profile has a single triplet.

Returns the split of the triplet if the profile contains exactly one triplet. If that triplet is a star tree, returns None. If the profile has multiple triplets, returns None (since there would be multiple splits).

The result is cached after first computation.

Returns:

The split of the single triplet, or None if multiple triplets or star tree.

Return type:

Split | None

property taxa: frozenset[str]#

Get the taxa of the profile.

Returns:

The 3 taxon labels.

Return type:

frozenset[str]

property triplets: Mapping[Triplet, float]#

Get the triplets and their weights (read-only).

Returns:

Read-only mapping of triplets to weights.

Return type:

Mapping[Triplet, float]

Triplet profile set module.

A triplet profile set is a collection of triplet profiles covering multiple three-taxon sets. This module provides the TripletProfileSet class.

class phylozoo.core.triplet.tprofileset.TripletProfileSet(profiles: list[TripletProfile | Triplet | tuple[TripletProfile, float]] | None = None, taxa: frozenset[str] | None = None)[source]#

Bases: object

Immutable collection of triplet profiles with two-level weights.

A TripletProfileSet groups triplets by their 3-taxon sets into profiles. Each profile has a weight (profile weight), and each triplet within a profile also has a weight (triplet weight).

This allows representing uncertainty or multiple hypotheses about triplet topologies for the same set of 3 taxa, with different weights assigned to each hypothesis.

Parameters:
  • profiles (list[TripletProfile | Triplet | tuple[TripletProfile, float]] | None, optional) –

    List of TripletProfile objects, Triplet objects, or tuples with profile weights.

    • If TripletProfile: used directly (optionally with a profile-weight tuple).

    • If Triplet: automatically grouped by taxa into profiles. For each 3-taxon set, all triplets on that set are collected into a TripletProfile with equal weights \(1/k\) (where \(k\) is the number of triplets for that taxa set). Each resulting profile in the set receives default profile weight 1.0.

    • If tuple: (profile, weight) where weight is the profile weight.

    Passing triplets together with explicit weights (e.g. (Triplet, weight)) is not supported. To use non-uniform triplet weights within a profile, construct a TripletProfile explicitly and pass that (optionally with a profile weight).

    By default None.

  • taxa (frozenset[str] | None, optional) – Total set of taxa. If provided, must be a superset of all taxa in the profiles. Allows specifying taxa for which no profile exists. By default None (computed from profiles).

Raises:

PhyloZooValueError – If any profile would be empty, if any weight is non-positive, if profiles/triplets are mixed incorrectly, or if provided taxa is not a superset of profile taxa.

Examples

>>> from phylozoo.core.split.base import Split
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> t3 = Triplet(Split({4}, {5, 6}))
>>> # From triplets (grouped into profiles, equal weights per profile)
>>> profileset = TripletProfileSet(profiles=[t1, t2, t3])
>>> len(profileset)
2
>>> profileset.get_profile_weight(frozenset({1, 2, 3}))
1.0
>>> # From TripletProfile objects (better control)
>>> profile1 = TripletProfile({t1: 0.8, t2: 0.2})
>>> profile2 = TripletProfile([t3])
>>> profileset2 = TripletProfileSet(profiles=[(profile1, 2.0), (profile2, 1.5)])
>>> profileset2.get_profile_weight(frozenset({1, 2, 3}))
2.0
__contains__(taxa: frozenset[str]) bool[source]#

Check if a profile exists for the given 3-taxon set.

Parameters:

taxa (frozenset[str]) – The 3-taxon set.

Returns:

True if a profile exists, False otherwise.

Return type:

bool

__iter__() Iterator[tuple[TripletProfile, float]][source]#

Return an iterator over (profile, profile_weight) pairs.

Returns:

Iterator over (profile, weight) tuples.

Return type:

Iterator[tuple[TripletProfile, float]]

__len__() int[source]#

Return the number of profiles.

Returns:

Number of profiles.

Return type:

int

__repr__() str[source]#

Return string representation of the profile set that can be used to initialize it.

Returns:

String representation that can be used to recreate the object.

Return type:

str

__str__() str[source]#

Return human-readable string representation of the triplet profile set.

Displays one line per profile, showing the profile (using its __str__ method) and its profile weight. Aligns with TripletProfile’s __str__ format.

Returns:

Human-readable string representation.

Return type:

str

Examples

>>> from phylozoo.core.split.base import Split
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> profile1 = TripletProfile({t1: 0.8, t2: 0.2})
>>> profileset = TripletProfileSet(profiles=[(profile1, 1.0)])
>>> str(profileset)
'TripletProfileSet({\n  TripletProfile({...}) [weight: 1.0]\n})'
all_profile_taxon_sets() Iterator[frozenset[str]][source]#

Get all 3-taxon sets that have profiles.

Returns:

Iterator over all 3-taxon sets that have profiles.

Return type:

Iterator[frozenset[str]]

get_profile(taxa: frozenset[str]) TripletProfile | None[source]#

Get the profile for a 3-taxon set.

Parameters:

taxa (frozenset[str]) – The 3-taxon set.

Returns:

The profile for the taxa, or None if not found.

Return type:

TripletProfile | None

get_profile_weight(taxa: frozenset[str]) float | None[source]#

Get the profile weight for a 3-taxon set.

Parameters:

taxa (frozenset[str]) – The 3-taxon set.

Returns:

The profile weight, or None if not found.

Return type:

float | None

has_profile(taxa: frozenset[str]) bool[source]#

Check if a profile exists for the given 3-taxon set.

Parameters:

taxa (frozenset[str]) – The 3-taxon set.

Returns:

True if a profile exists, False otherwise.

Return type:

bool

property is_all_resolved: bool#

Check if all profiles in the set are resolved.

A profile is resolved if all its triplets are resolved (i.e., not star trees). This property returns True only if every profile in the set is resolved.

Returns:

True if all profiles are resolved, False otherwise.

Return type:

bool

Examples

>>> from phylozoo.core.split.base import Split
>>> from phylozoo.core.triplet.base import Triplet
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({4}, {5, 6}))
>>> profileset = TripletProfileSet(profiles=[t1, t2])
>>> profileset.is_all_resolved
True
>>> star = Triplet({1, 2, 3})
>>> profileset2 = TripletProfileSet(profiles=[t2, star])
>>> profileset2.is_all_resolved
False
property is_dense: bool#

Check if the triplet profile set is dense.

A dense triplet profile set has a profile for every possible combination of 3 taxa from the total set of taxa.

Returns:

True if the profile set is dense (has C(n, 3) profiles where n is the number of taxa), False otherwise.

Return type:

bool

property max_profile_len: int#

Get the maximum number of triplets in any profile.

Returns:

The largest number of triplets in any profile in the set. Returns 0 if the set is empty.

Return type:

int

Examples

>>> from phylozoo.core.split.base import Split
>>> from phylozoo.core.triplet.base import Triplet
>>> t1 = Triplet(Split({1}, {2, 3}))
>>> t2 = Triplet(Split({2}, {1, 3}))
>>> t3 = Triplet(Split({3}, {1, 2}))
>>> profileset = TripletProfileSet(profiles=[t1, t2, t3])
>>> profileset.max_profile_len
3
property profiles: Mapping[frozenset[str], tuple[TripletProfile, float]]#

Get the profiles and their weights (read-only).

Returns:

Read-only mapping of 3-taxon sets to (profile, profile_weight) tuples.

Return type:

Mapping[frozenset[str], tuple[TripletProfile, float]]

property taxa: frozenset[str]#

Get all taxa in the profile set.

Returns:

Set of all taxon labels. If taxa was specified during initialization, this includes all specified taxa (even those without profiles). Otherwise, returns taxa that appear in at least one profile.

Return type:

frozenset[str]