<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def linearization_error(nodes):
 r"""Compute the maximum error of a linear approximation. .. note:: There is also a Fortran implementation of this function, which will be used if it can be built. .. note:: This is a helper for :class:`.Linearization`, which is used during the curve-curve intersection process. We use the line .. math:: L(s) = v_0 (1 - s) + v_n s and compute a bound on the maximum error .. math:: \max_{s \in \left[0, 1\right]} \|B(s) - L(s)\|_2. Rather than computing the actual maximum (a tight bound), we use an upper bound via the remainder from Lagrange interpolation in each component. This leaves us with :math:`\frac{s(s - 1)}{2!}` times the second derivative in each component. The second derivative curve is degree :math:`d = n - 2` and is given by .. math:: B''(s) = n(n - 1) \sum_{j = 0}^{d} \binom{d}{j} s^j (1 - s)^{d - j} \cdot \Delta^2 v_j Due to this form (and the convex combination property of B |eacute| zier Curves) we know each component of the second derivative will be bounded by the maximum of that component among the :math:`\Delta^2 v_j`. For example, the curve .. math:: B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^2 + \left[\begin{array}{c} 3 \\ 1 \end{array}\right] 2s(1 - s) + \left[\begin{array}{c} 9 \\ -2 \end{array}\right] s^2 has :math:`B''(s) \equiv \left[\begin{array}{c} 6 \\ -8 \end{array}\right]` which has norm :math:`10` everywhere, hence the maximum error is .. math:: \left.\frac{s(1 - s)}{2!} \cdot 10\right|_{s = \frac{1}{2}} = \frac{5}{4}. .. image:: ../images/linearization_error.png :align: center .. testsetup:: linearization-error, linearization-error-fail import numpy as np import bezier from bezier._geometric_intersection import linearization_error .. doctest:: linearization-error 1.25 .. testcleanup:: linearization-error import make_images make_images.linearization_error(nodes) As a **non-example**, consider a "pathological" set of control points: .. math:: B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^3 + \left[\begin{array}{c} 5 \\ 12 \end{array}\right] 3s(1 - s)^2 + \left[\begin{array}{c} 10 \\ 24 \end{array}\right] 3s^2(1 - s) + \left[\begin{array}{c} 30 \\ 72 \end{array}\right] s^3 By construction, this lies on the line :math:`y = \frac{12x}{5}`, but the parametrization is cubic: :math:`12 \cdot x(s) = 5 \cdot y(s) = 180s(s^2 + 1)`. Hence, the fact that the curve is a line is not accounted for and we take the worse case among the nodes in: .. math:: B''(s) = 3 \cdot 2 \cdot \left( \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s) + \left[\begin{array}{c} 15 \\ 36 \end{array}\right] s\right) which gives a nonzero maximum error: .. doctest:: linearization-error-fail 29.25 Though it may seem that ``0`` is a more appropriate answer, consider the **goal** of this function. We seek to linearize curves and then intersect the linear approximations. Then the :math:`s`-values from the line-line intersection is lifted back to the curves. Thus the error :math:`\|B(s) - L(s)\|_2` is more relevant than the underyling algebraic curve containing :math:`B(s)`. .. note:: It may be more appropriate to use a **relative** linearization error rather than the **absolute** error provided here. It's unclear if the domain :math:`\left[0, 1\right]` means the error is **already** adequately scaled or if the error should be scaled by the arc length of the curve or the (easier-to-compute) length of the line. Args: nodes (numpy.ndarray):
 Nodes of a curve. Returns: float: The maximum error between the curve and the linear approximation. """

    _, num_nodes = nodes.shape
    degree = num_nodes - 1
    if degree == 1:
        return 0.0

    second_deriv = nodes[:, :-2] - 2.0 * nodes[:, 1:-1] + nodes[:, 2:]
    worst_case = np.max(np.abs(second_deriv), axis=1)
    # max_{0 <= s <= 1} s(1 - s)/2 = 1/8 = 0.125
    multiplier = 0.125 * degree * (degree - 1)
    # NOTE: worst_case is 1D due to np.max(), so this is the vector norm.
    return multiplier * np.linalg.norm(worst_case, ord=2)