Skip to content

Hopf

The Hopf normal form, whose focus gives birth to a limit cycle of radius √(-μ / a) as μ crosses 0.

  • Name: hopf_form
  • Field: mathematics/dynamical_systems
  • Formalism: ordinary differential equations
  • References: Gros 2015; Dilão 2023

Factory

@register_model(
    field='mathematics/dynamical_systems',
    tags=('bifurcation', 'normal form', 'ode', 'limit cycle'),
    references=('Gros 2015', 'Dilão 2023'),
    defaults={'until': 50.0, 'dt': 0.1},
)
def hopf_form(x: float = 0.1, y: float = 0.0, *, mu: float = 0.25, omega: float = 1.0, a: float = -1.0) -> System:
    """Return the Hopf normal form, whose focus gives birth to a limit cycle of radius `√(-μ / a)` as μ crosses 0.

    `x' = μx - ωy + a x (x² + y²)` and `y' = ωx + μy + a y (x² + y²)`, supercritical for `a < 0`.

    Args:
        x:
            The initial first coordinate.

        y:
            The initial second coordinate.

        mu:
            The bifurcation parameter.

        omega:
            The angular frequency.

        a:
            The cubic coefficient, the sign of the first Lyapunov coefficient.

    Returns:
        system:
            The model, with the states `form.x` and `form.y`.

    Examples:
        >>> from skcomplex.models.mathematics.dynamical_systems import hopf_form
        >>> hopf_form(mu=-0.1).elements[0].mu
        -0.1
    """
    return System(elements=[HopfElement('form', x=x, y=y, mu=mu, omega=omega, a=a)])

Components

class HopfElement(Element):
    """Normal form of the Hopf bifurcation in Cartesian coordinates, with the radial law `r' = mu r + a r^3`.

    Args:
        label:
            The label of the element.

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

        x:
            The initial real part.

        y:
            The initial imaginary part.

        mu:
            The bifurcation parameter.

        omega:
            The angular frequency.

        a:
            The cubic coefficient, negative for the supercritical bifurcation.

    Examples:
        >>> from skcomplex.models.mathematics.dynamical_systems import HopfElement
        >>> HopfElement('form', mu=0.5).mu
        0.5
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        x: Annotated[object, StateSpec()] = 0.1,
        y: Annotated[object, StateSpec()] = 0.0,
        mu: Annotated[object, ParameterSpec()] = 0.25,
        omega: Annotated[object, ParameterSpec()] = 1.0,
        a: Annotated[object, ParameterSpec()] = -1.0,
    ) -> None:
        super().__init__(label, visual=visual)
        self.x = x
        self.y = y
        self.mu = mu
        self.omega = omega
        self.a = a

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the rates of the real and the imaginary part.

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

        Returns:
            laws:
                The laws of the element.
        """
        return [
            RateLaw(s.x, s.mu * s.x - s.omega * s.y + s.a * s.x * (s.x**2 + s.y**2)),
            RateLaw(s.y, s.omega * s.x + s.mu * s.y + s.a * s.y * (s.x**2 + s.y**2)),
        ]

Equations

form.x: diff(x_form(t), t) == (x_form(t)^2 + y_form(t)^2)*a_form*x_form(t) + mu_form*x_form(t) - omega_form*y_form(t)
form.y: diff(y_form(t), t) == (x_form(t)^2 + y_form(t)^2)*a_form*y_form(t) + omega_form*x_form(t) + mu_form*y_form(t)