def logistic_map(x, steps, r=4):
  r"""
  Generates a time series of the logistic map.

  Characteristics and Background:
    The logistic map is among the simplest examples for a time series that can
    exhibit chaotic behavior depending on the parameter r. For r between 2 and 
    3, the series quickly becomes static. At r=3 the first bifurcation point is
    reached after which the series starts to oscillate. Beginning with r = 3.6
    it shows chaotic behavior with a few islands of stability until perfect
    chaos is achieved at r = 4.

  Calculating the Lyapunov exponent:
    To calculate the "true" Lyapunov exponent of the logistic map, we first
    have to make a few observations for maps in general that are repeated
    applications of a function to a starting value.

    If we have two starting values that differ by some infinitesimal 
    :math:`delta_0` then according to the definition of the lyapunov exponent
    we will have an exponential divergence:

    .. math::
      |\delta_n| = |\delta_0| e^{\lambda n}

    We can now write that:

    .. math::
      e^{\lambda n} = \lim_{\delta_0 -> 0} |\frac{\delta_n}{\delta_0}|

    This is the definition of the derivative :math:`\frac{dx_n}{dx_0}` of a
    point :math:`x_n` in the time series with respect to the starting point
    :math:`x_0` (or rather the absolute value of that derivative). Now we can
    use the fact that due to the definition of our map as repetitive
    application of some f we have:

    .. math::
      f^{n\prime}(x) = f(f(f(...f(x_0)...))) = f'(x_n-1) \cdot f'(x_n-2)
      \cdot ... \cdot f'(x_0)

    with

    .. math::
      e^{\lambda n} = |f^{n\prime}(x)|

    we now have

    .. math::

      e^{\lambda n} &= |f'(x_n-1) \cdot f'(x_n-2) \cdot ... \cdot f'(x_0)| \\
      \Leftrightarrow \\
      \lambda n &= \ln |f'(x_n-1) \cdot f'(x_n-2) \cdot ... \cdot f'(x_0)| \\
      \Leftrightarrow \\
      \lambda &= \frac{1}{n} \ln |f'(x_n-1) \cdot f'(x_n-2) \cdot ... \cdot f'(x_0)| \\
             &= \frac{1}{n} \sum_{k=0}^{n-1} \ln |f'(x_k)|

    With this sum we can now calculate the lyapunov exponent for any map.
    For the logistic map we simply have to calculate :math:`f'(x)` and as we
    have

    .. math::
      f(x) = r x (1-x) = rx - rx²

    we now get

    .. math::
      f'(x) = r - 2 rx



  References:
    .. [lm_1] https://en.wikipedia.org/wiki/Tent_map
    .. [lm_2] https://blog.abhranil.net/2015/05/15/lyapunov-exponent-of-the-logistic-map-mathematica-code/

  Args:
    x (float):
      starting point
    steps (int):
      number of steps for which the generator should run

  Kwargs:
    r (int):
      parameter r that controls the behavior of the map

  Returns:
    generator object:
      the generator that creates the time series
  """
  for _ in range(steps):
    x = r * x * (1 - x)
    yield x
r"""
  Generates a time series of the logistic map.

  Characteristics and Background:
    The logistic map is among the simplest examples for a time series that can
    exhibit chaotic behavior depending on the parameter r. For r between 2 and 
    3, the series quickly becomes static. At r=3 the first bifurcation point is
    reached after which the series starts to oscillate. Beginning with r = 3.6
    it shows chaotic behavior with a few islands of stability until perfect
    chaos is achieved at r = 4.

  Calculating the Lyapunov exponent:
    To calculate the "true" Lyapunov exponent of the logistic map, we first
    have to make a few observations for maps in general that are repeated
    applications of a function to a starting value.

    If we have two starting values that differ by some infinitesimal 
    :math:`delta_0` then according to the definition of the lyapunov exponent
    we will have an exponential divergence:

    .. math::
      |\delta_n| = |\delta_0| e^{\lambda n}

    We can now write that:

    .. math::
      e^{\lambda n} = \lim_{\delta_0 -> 0} |\frac{\delta_n}{\delta_0}|

    This is the definition of the derivative :math:`\frac{dx_n}{dx_0}` of a
    point :math:`x_n` in the time series with respect to the starting point
    :math:`x_0` (or rather the absolute value of that derivative). Now we can
    use the fact that due to the definition of our map as repetitive
    application of some f we have:

    .. math::
      f^{n\prime}(x) = f(f(f(...f(x_0)...))) = f'(x_n-1) \cdot f'(x_n-2)
      \cdot ... \cdot f'(x_0)

    with

    .. math::
      e^{\lambda n} = |f^{n\prime}(x)|

    we now have

    .. math::

      e^{\lambda n} &= |f'(x_n-1) \cdot f'(x_n-2) \cdot ... \cdot f'(x_0)| \\
      \Leftrightarrow \\
      \lambda n &= \ln |f'(x_n-1) \cdot f'(x_n-2) \cdot ... \cdot f'(x_0)| \\
      \Leftrightarrow \\
      \lambda &= \frac{1}{n} \ln |f'(x_n-1) \cdot f'(x_n-2) \cdot ... \cdot f'(x_0)| \\
             &= \frac{1}{n} \sum_{k=0}^{n-1} \ln |f'(x_k)|

    With this sum we can now calculate the lyapunov exponent for any map.
    For the logistic map we simply have to calculate :math:`f'(x)` and as we
    have

    .. math::
      f(x) = r x (1-x) = rx - rx²

    we now get

    .. math::
      f'(x) = r - 2 rx



  References:
    .. [lm_1] https://en.wikipedia.org/wiki/Tent_map
    .. [lm_2] https://blog.abhranil.net/2015/05/15/lyapunov-exponent-of-the-logistic-map-mathematica-code/

  Args:
    x (float):
      starting point
    steps (int):
      number of steps for which the generator should run

  Kwargs:
    r (int):
      parameter r that controls the behavior of the map

  Returns:
    generator object:
      the generator that creates the time series