Skip to content

Generalized tent map

An ensemble of the skew tent map, whose density relaxes to the uniform invariant density for any a.

  • Name: skew_tent_map
  • Field: mathematics/dynamical_systems
  • Formalism: discrete map
  • References: Bertin 2021

Factory

@register_model(
    field='mathematics/dynamical_systems',
    tags=('chaos', 'discrete map', 'piecewise linear', 'invariant density'),
    references=('Bertin 2021',),
    defaults={'until': 50, 'dt': 1},
)
def skew_tent_map(
    n_points: int = 100,
    *,
    a: float = 0.3,
    x: float = 0.4,
    spread: float = 0.01,
    random_state: int | np.random.Generator | None = 0,
) -> System:
    """Return an ensemble of the skew tent map, whose density relaxes to the uniform invariant density for any `a`.

    The map is `x' = x / a` for `x < a` and `x' = (1 - x) / (1 - a)` otherwise. Every value has one preimage on each
    branch, with slopes `1 / a` and `1 / (1 - a)`, so the uniform density is invariant. The points start in a narrow
    interval and spread over the unit interval until their histogram is flat. For `a = 1/2` both slopes are 2, and in
    floating point every orbit reaches 0 within about 55 steps, so `a` should differ from 1/2.

    Args:
        n_points:
            The number of points of the ensemble.

        a:
            The position of the top of the tent, between 0 and 1.

        x:
            The left end of the interval of initial points.

        spread:
            The width of the interval of initial points.

        random_state:
            The seed or generator of the initial points.

    Returns:
        system:
            The model, with the states `points.x`.

    Examples:
        >>> from skcomplex.models.mathematics.dynamical_systems import skew_tent_map
        >>> skew_tent_map(10, a=0.7).elements[0].values['a']
        0.7
    """
    start = _draw_cloud(n_points, x, spread, random_state)
    return System(
        elements=[GroupElement('points', element=SkewTentMapElement, size=n_points, values={'x': start, 'a': a})],
    )

Components

class SkewTentMapElement(Element):
    """Skew tent map `x' = x / a` below the peak `a` and `(1 - x) / (1 - a)` above it.

    Args:
        label:
            The label of the element.

        visual:
            How the element is drawn, or `None` for `default_visual_`.

        x:
            The initial value, between 0 and 1.

        a:
            The position of the peak, between 0 and 1.

    Examples:
        >>> from skcomplex.models.mathematics.dynamical_systems import SkewTentMapElement
        >>> SkewTentMapElement('point', a=0.5).a
        0.5
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        x: Annotated[object, StateSpec()] = 0.4,
        a: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.3,
    ) -> None:
        super().__init__(label, visual=visual)
        self.x = x
        self.a = a

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the next value.

        Args:
            s:
                The namespace of the symbols the laws can use.

        Returns:
            laws:
                The laws of the element.
        """
        return [UpdateLaw(s.x, where(s.x < s.a, s.x / s.a, (1 - s.x) / (1 - s.a)))]

Equations

points.x[i]: x_points(t + 1) == where(x_points(t) < a_points, x_points(t)/a_points, (x_points(t) - 1)/(a_points - 1))