Source code for thompson.orbits

"""
.. testsetup::
	
	from thompson        import *
	from thompson.orbits import *
"""

from collections import namedtuple

from .number_theory import SolutionSet
from .word import format
from .generators import Generators

__all__ = ["ComponentType", "Characteristic", "print_component_types", "SolutionSet"]

BaseComponentType = namedtuple("BaseComponentType", "type characteristic")
[docs]class ComponentType(BaseComponentType): r"""This class is essentially a glorified :mod:`enumeration <py3:enum>`: its instances store a number from 1 to 5 to represent the type of a component. :ivar characteristic: Either the characteristic :math:`(m, \Gamma)` of this component, or ``None`` if this component has no characteristic. Periodic components have characteristic :math:`(m, \varepsilon)`, where :math:`\varepsilon` is the empty word. .. seealso:: Section :paperref:`SNF` of the paper. """ _complete_infinite = 1 _complete_finite = 2 _right_semi_infinite = 3 _left_semi_infinite = 4 _incomplete = 5 _names = { 1: "Bi-infinite", 2: "Periodic", 3: "Right semi-infinite", 4: "Left semi-infinite", 5: "Incomplete" } #Like vanilla namedtuples, do not allow any instance attributes. __slots__ = ()
[docs] @classmethod def periodic(cls, period): """Describes a complete finite (i.e. periodic, type 2) component. The argument is the period of the the component.""" return cls(cls._complete_finite, Characteristic(period, tuple()))
[docs] @classmethod def semi_infinite(cls, characteristic, backward=False): """Describes a semi-infinite component (types 3, 4). The first argument is the characteristic of the component; use ``None`` if this component doesn't have a characteristic. The second argument should specify where this component is left or right semi-infinite.""" if characteristic is not None and len(characteristic[1]) == 0: raise ValueError('Semi-infinite components cannot have a trivial characteristic multiplier.') if characteristic is not None: assert (characteristic[0] < 0) == backward, (characteristic, backward) type = cls._left_semi_infinite if backward else cls._right_semi_infinite return cls(type, characteristic)
[docs] @classmethod def complete_infinite(cls): """Describes a component which is infinite in both directions (type 1).""" return cls(cls._complete_infinite, None)
[docs] @classmethod def incomplete(cls): """Describes a component which is incomplete finite (type 5).""" return cls(cls._incomplete, None)
def __str__(self): output = "{} component".format(self._names[self.type]) if self.type is self._complete_finite: output += " of order {}".format(self.characteristic[0]) if self.type == self._left_semi_infinite or self.type == self._right_semi_infinite: if self.characteristic is not None: output += " with characteristic ({}, {})".format( self.characteristic[0], format(self.characteristic[1])) else: output += " with no characteristic" return output
[docs] def is_type_A(self): """Returns true if this component belongs to an orbit of type A (periodic).""" return self.characteristic is not None and len(self.characteristic[1]) == 0
[docs] def is_type_B(self): """Returns true if this component belongs to an orbit of type B (has a characteristic)""" return self.characteristic is not None and len(self.characteristic[1]) > 0
[docs] def is_type_C(self): """Returns true if this component belongs to an orbit of type C (does not have a characteristic)""" return self.characteristic is None
[docs] def is_incomplete(self): """Returns True if this component is incomplete, otherwise False.""" return self.type is self._incomplete
[docs] def is_semi_infinite(self): """Returns True is this component is semi_infinite (with or without characteristic); otherwise returns False.""" return self.type is self._left_semi_infinite or self.type is self._right_semi_infinite
Characteristic = namedtuple("Characteristic", 'power multiplier') def _str(self): return "{}({}, {})".format( self.__class__.__name__, self.power, format(self.multiplier) ) Characteristic.__str__ = _str