Circular Orderings#

Working with Circular Orderings#

Circular orderings represent mathematical arrangements where elements are placed in a circle, with the first and last elements considered adjacent. PhyloZoo offers two classes: CircularOrdering for individual elements and CircularSetOrdering for grouped elements, both stored in canonical form for efficient mathematical operations.

CircularSetOrdering inherits from Partition, representing a partition with an additional circular ordering structure. CircularOrdering is a special case of CircularSetOrdering where each element is in its own singleton set.

Creating Circular Orderings#

Circular orderings can be created from any sequence of elements or sets:

from phylozoo.core.primitives import CircularOrdering, CircularSetOrdering

# Create circular ordering of individual elements
co = CircularOrdering([1, 2, 3, 4])

# Create circular ordering of sets (more general)
cso = CircularSetOrdering([{1, 2}, {3}, {4, 5}])

# From different input types
co_from_tuple = CircularOrdering((1, 2, 3, 4))
cso_from_list = CircularSetOrdering([[1, 2], [3], [4, 5]])

The constructor automatically converts inputs to the appropriate immutable types and validates that all elements are present and distinct.

Accessing Circular Ordering Properties#

Basic properties

Circular orderings provide access to their order, elements, and length:

# Access the element order (CircularOrdering)
order = co.order  # (1, 2, 3, 4)

# Access the set order (CircularSetOrdering)
set_order = cso.setorder  # ({1, 2}, {3}, {4, 5})

# Get all elements
elements = co.elements  # frozenset({1, 2, 3, 4})
set_elements = cso.elements  # frozenset({1, 2, 3, 4, 5})

# Get number of components
num_elements = len(co)  # 4
num_sets = len(cso)     # 3

Canonical representations

Circular orderings use canonical representations for equality. Two orderings are equal if they represent the same circular arrangement, regardless of starting position or direction:

# Different representations of the same circular ordering
co1 = CircularOrdering([1, 2, 3, 4])
co2 = CircularOrdering([2, 3, 4, 1])  # Rotated
co3 = CircularOrdering([4, 3, 2, 1])  # Reversed

# All represent the same circular arrangement
co1 == co2  # True
co1 == co3  # True
co2 == co3  # True

# Hashable for use in sets and dicts
ordering_set = {co1, co2, co3}  # Contains only one unique ordering

Circular Ordering Operations#

Neighbor checking

The are_neighbors() method determines whether two elements or sets are adjacent in the circular arrangement (neighbor relationships are symmetric and wrap around):

# Check element neighbors (CircularOrdering)
adjacent = co.are_neighbors(1, 2)    # True (consecutive)
wrapped = co.are_neighbors(1, 4)     # True (wraps around)
not_adjacent = co.are_neighbors(1, 3)  # False (not neighbors)

# Check set neighbors (CircularSetOrdering)
set_adjacent = cso.are_neighbors({1, 2}, {3})        # True
set_wrapped = cso.are_neighbors({1, 2}, {4, 5})      # True (wraps around)
set_not_adjacent = cso.are_neighbors({1, 2}, {4, 5})  # False in this case

Suborderings

The suborderings() (respectively, suborderings()) method yields all circular (set) orderings formed by selecting a subset of elements (respectively, sets) of a given size:

# All circular orderings of 2 elements from 5
co = CircularOrdering([1, 2, 3, 4, 5])
subs = list(co.suborderings(size=2))
len(subs)  # C(5, 2) = 10

# All circular set orderings of 2 sets from 5
cso = CircularSetOrdering([{1}, {2}, {3}, {4}, {5}])
set_subs = list(cso.suborderings(size=2))

Representative orderings

The representative_orderings() method yields all CircularOrdering instances with exactly one element chosen from each set in the circular set ordering.

cso = CircularSetOrdering([{1, 2}, {3}])
reps = list(cso.representative_orderings())
len(reps)  # 2 (two choices from first set, one from second)

Converting between CircularOrdering and CircularSetOrdering

The are_singletons() method checks if all sets in a CircularSetOrdering are singletons. If this is the case, the to_circular_ordering() method converts the CircularSetOrdering to a CircularOrdering.

cso = CircularSetOrdering([{1}, {2}, {3}])
singletons = cso.are_singletons() # True
co = cso.to_circular_ordering()

A CircularOrdering can be converted to a CircularSetOrdering using the to_circular_setordering() method.

co = CircularOrdering([1, 2, 3])
cso = co.to_circular_setordering()

See Also#

  • API Reference - Complete function signatures and detailed examples

  • Partition - Set partitions forming the basis of the circular ordering