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))