Skip to content

Langford attractor

The Langford flow, a rotation whose torus breaks into a strange attractor for the defaults of Dilão.

  • Name: langford
  • Field: mathematics/dynamical_systems
  • Formalism: ordinary differential equations
  • References: Langford 1984; Dilão 2023

Select this system

from skcomplex.systems import create_simulation, create_system, describe

system = create_system('langford')
entry = describe('langford')
trajectory = create_simulation('langford').prepare().run().trajectory_

Factory

@register_system(
    field='mathematics/dynamical_systems',
    tags=('chaos', 'ode', 'torus', 'strange attractor'),
    references=('Langford 1984', 'Dilão 2023'),
    defaults={'until': 200.0, 'dt': 0.05},
)
def langford(
    x: float = 0.1,
    y: float = 0.0,
    z: float = 0.0,
    *,
    a: float = 0.95,
    b: float = 0.7,
    c: float = 0.6,
    d: float = 3.5,
    e: float = 0.25,
    f: float = 0.1,
) -> System:
    """Return the Langford flow, a rotation whose torus breaks into a strange attractor for the defaults of Dilão.

    The flow is `x' = (z - b) x - d y`, `y' = d x + (z - b) y`, and
    `z' = c + a z - z³ / 3 - (x² + y²)(1 + e z) + f z x³`, with the reference parameters of Dilão (2023, Exercise
    3.22). Without `f` the flow is symmetric under rotations about the `z` axis.

    Args:
        x:
            The initial first coordinate.

        y:
            The initial second coordinate.

        z:
            The initial height.

        a:
            The linear growth of the height.

        b:
            The height above which the rotation grows.

        c:
            The constant drive of the height.

        d:
            The angular frequency of the rotation.

        e:
            The coupling of the radius and the height.

        f:
            The term that breaks the rotational symmetry.

    Returns:
        system:
            The system, with the states `langford.x`, `langford.y`, and `langford.z`.

    Examples:
        >>> from skcomplex.systems.mathematics.dynamical_systems import langford
        >>> langford(f=0.0).elements[0].f
        0.0
    """
    return System(elements=[LangfordElement('langford', x=x, y=y, z=z, a=a, b=b, c=c, d=d, e=e, f=f)])

Components

Elements:

  • LangfordElement, from Element
class LangfordElement(Element):
    """Langford flow, a rotation in `x, y` whose radius and height `z` couple into a torus that breaks into chaos.

    The flow is `x' = (z - b) x - d y`, `y' = d x + (z - b) y`, and
    `z' = c + a z - z³ / 3 - (x² + y²)(1 + e z) + f z x³`.

    Args:
        label:
            The label of the element.

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

        x:
            The initial first coordinate.

        y:
            The initial second coordinate.

        z:
            The initial height.

        a:
            The linear growth of the height.

        b:
            The height above which the rotation grows.

        c:
            The constant drive of the height.

        d:
            The angular frequency of the rotation.

        e:
            The coupling of the radius and the height.

        f:
            The term that breaks the rotational symmetry.

    Examples:
        >>> from skcomplex.systems.mathematics.dynamical_systems import LangfordElement
        >>> LangfordElement('langford', d=3.0).d
        3.0
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        x: Annotated[object, StateSpec()] = 0.1,
        y: Annotated[object, StateSpec()] = 0.0,
        z: Annotated[object, StateSpec()] = 0.0,
        a: Annotated[object, ParameterSpec()] = 0.95,
        b: Annotated[object, ParameterSpec()] = 0.7,
        c: Annotated[object, ParameterSpec()] = 0.6,
        d: Annotated[object, ParameterSpec()] = 3.5,
        e: Annotated[object, ParameterSpec()] = 0.25,
        f: Annotated[object, ParameterSpec()] = 0.1,
    ) -> None:
        super().__init__(label, visual=visual)
        self.x = x
        self.y = y
        self.z = z
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the rates of the three coordinates.

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

        Returns:
            laws:
                The laws of the element.
        """
        radius = s.x**2 + s.y**2
        return [
            RateLaw(s.x, (s.z - s.b) * s.x - s.d * s.y),
            RateLaw(s.y, s.d * s.x + (s.z - s.b) * s.y),
            RateLaw(s.z, s.c + s.a * s.z - s.z**3 / 3 - radius * (1 + s.e * s.z) + s.f * s.z * s.x**3),
        ]

Equations

langford.x: diff(x_langford(t), t) == -(b_langford - z_langford(t))*x_langford(t) - d_langford*y_langford(t)
langford.y: diff(y_langford(t), t) == d_langford*x_langford(t) - (b_langford - z_langford(t))*y_langford(t)
langford.z: diff(z_langford(t), t) == f_langford*x_langford(t)^3*z_langford(t) - 1/3*z_langford(t)^3 - (x_langford(t)^2 + y_langford(t)^2)*(e_langford*z_langford(t) + 1) + a_langford*z_langford(t) + c_langford