def newton_iterate(evaluate_fn, s, t):
    r"""Perform a Newton iteration.

    In this function, we assume that :math:`s` and :math:`t` are nonzero,
    this makes convergence easier to detect since "relative error" at
    ``0.0`` is not a useful measure.

    There are several tolerance / threshold quantities used below:

    * :math:`10` (:attr:`MAX_NEWTON_ITERATIONS`) iterations will be done before
      "giving up". This is based on the assumption that we are already starting
      near a root, so quadratic convergence should terminate quickly.
    * :math:`\tau = \frac{1}{4}` is used as the boundary between linear
      and superlinear convergence. So if the current error
      :math:`\|p_{n + 1} - p_n\|` is not smaller than :math:`\tau` times
      the previous error :math:`\|p_n - p_{n - 1}\|`, then convergence
      is considered to be linear at that point.
    * :math:`\frac{2}{3}` of all iterations must be converging linearly
      for convergence to be stopped (and moved to the next regime). This
      will only be checked after 4 or more updates have occurred.
    * :math:`\tau = 2^{-42}` (:attr:`NEWTON_ERROR_RATIO`) is used to
      determine that an update is sufficiently small to stop iterating. So if
      the error :math:`\|p_{n + 1} - p_n\|` smaller than :math:`\tau` times
      size of the term being updated :math:`\|p_n\|`, then we
      exit with the "correct" answer.

    It is assumed that ``evaluate_fn`` will use a Jacobian return value of
    :data:`None` to indicate that :math:`F(s, t)` is exactly ``0.0``. We
    **assume** that if the function evaluates to exactly ``0.0``, then we are
    at a solution. It is possible however, that badly parameterized curves
    can evaluate to exactly ``0.0`` for inputs that are relatively far away
    from a solution (see issue #21).

    Args:
        evaluate_fn (Callable[Tuple[float, float], tuple]): A callable
            which takes :math:`s` and :math:`t` and produces an evaluated
            function value and the Jacobian matrix.
        s (float): The (first) parameter where the iteration will start.
        t (float): The (second) parameter where the iteration will start.

    Returns:
        Tuple[bool, float, float]: The triple of

        * Flag indicating if the iteration converged.
        * The current :math:`s` value when the iteration stopped.
        * The current :math:`t` value when the iteration stopped.
    """
    # Several quantities will be tracked throughout the iteration:
    # * norm_update_prev: ||p{n}   - p{n-1}|| = ||dp{n-1}||
    # * norm_update     : ||p{n+1} - p{n}  || = ||dp{n}  ||
    # * linear_updates  : This is a count on the number of times that
    #                     ``dp{n}`` "looks like" ``dp{n-1}`` (i.e.
    #                     is within a constant factor of it).
    norm_update_prev = None
    norm_update = None
    linear_updates = 0  # Track the number of "linear" updates.
    current_s = s
    current_t = t
    for index in six.moves.xrange(MAX_NEWTON_ITERATIONS):
        jacobian, func_val = evaluate_fn(current_s, current_t)
        if jacobian is None:
            return True, current_s, current_t

        singular, delta_s, delta_t = _helpers.solve2x2(
            jacobian, func_val[:, 0]
        )
        if singular:
            break

        norm_update_prev = norm_update
        norm_update = np.linalg.norm([delta_s, delta_t], ord=2)
        # If ||p{n} - p{n-1}|| > 0.25 ||p{n-1} - p{n-2}||, then that means
        # our convergence is acting linear at the current step.
        if index > 0 and norm_update > 0.25 * norm_update_prev:
            linear_updates += 1
        # If ``>=2/3`` of the updates have been linear, we are near a
        # non-simple root. (Make sure at least 5 updates have occurred.)
        if index >= 4 and 3 * linear_updates >= 2 * index:
            break

        # Determine the norm of the "old" solution before updating.
        norm_soln = np.linalg.norm([current_s, current_t], ord=2)
        current_s -= delta_s
        current_t -= delta_t
        if norm_update < NEWTON_ERROR_RATIO * norm_soln:
            return True, current_s, current_t

    return False, current_s, current_t