Exemplo n.º 1
0
def root_info(n, ctx):
    coeffs = get_coeffs(n)
    root = find_best_solution(n, ctx)
    cond = condition_number(n, root)
    # We know the root is in [1/4, 1/3] so this starts outside that interval.
    s0 = 0.5
    s1_converged = de_casteljau.basic_newton(s0, coeffs)
    s2_converged = de_casteljau.accurate_newton(s0, coeffs)
    s3_converged = de_casteljau.full_newton(s0, coeffs)

    rel_error1 = plot_utils.to_float(abs((s1_converged - root) / root))
    rel_error2 = plot_utils.to_float(abs((s2_converged - root) / root))
    rel_error3 = plot_utils.to_float(abs((s3_converged - root) / root))
    if rel_error1 == 0:
        raise RuntimeError(
            "Unexpected error for basic Newton.", n, root, s1_converged
        )
    if rel_error2 == 0:
        raise RuntimeError(
            "Unexpected error for accurate Newton.", n, root, s2_converged
        )
    if rel_error3 == 0:
        raise RuntimeError(
            "Unexpected error for full Newton.", n, root, s3_converged
        )

    return cond, rel_error1, rel_error2, rel_error3
Exemplo n.º 2
0
def add_plot(ax, ctx, n, d):
    # (1 - 5s) = 2^d (3s - 1) = (1 + w) (3s - 1)
    w_vals = [ctx.root(2.0**d, n, k=k) - 1 for k in range(n)]
    x_vals = []
    y_vals = []
    for w in w_vals:
        root = (2 + w) / (8 + 3 * w)
        x_vals.append(plot_utils.to_float(root.real))
        y_vals.append(plot_utils.to_float(root.imag))

    ax.plot(x_vals, y_vals, marker="o", markersize=2.0, linestyle="none")
    ax.set_title("$n = {}$".format(n), fontsize=plot_utils.TEXT_SIZE)
Exemplo n.º 3
0
def root_info(n):
    coeffs = get_coeffs(n)
    root = find_best_solution(n)
    cond = condition_number(n, root)
    # We know the root is in [1, 2) so this starts outside that interval.
    x1_converged = horner.basic_newton(2.0, coeffs)
    x2_converged = horner.accurate_newton(2.0, coeffs)
    x3_converged = horner.full_newton(2.0, coeffs)

    rel_error1 = plot_utils.to_float(abs((x1_converged - root) / root))
    rel_error2 = plot_utils.to_float(abs((x2_converged - root) / root))
    rel_error3 = plot_utils.to_float(abs((x3_converged - root) / root))
    if rel_error1 == 0:
        raise RuntimeError("Unexpected error for basic Newton.")
    if rel_error2 == 0:
        raise RuntimeError("Unexpected error for accurate Newton.")
    if rel_error3 == 0:
        raise RuntimeError("Unexpected error for full Newton.")

    return cond, rel_error1, rel_error2, rel_error3
Exemplo n.º 4
0
def condition_number(n, root):
    r"""Compute the condition number of :math:`p(x)` at a root.

    When :math:`p(x) = (x - 1)^n - 2^{-31}` is written in the monomial basis,
    we have :math:`\widetilde{p}(x) = (x + 1)^n - (-1)^n 2^{-31}`.
    """
    if root <= 0:
        raise ValueError("Expected positive root.", root)
    p_tilde = (root + 1)**n - (-1)**n * 0.5**31
    dp = n * (root - 1)**(n - 1)
    return plot_utils.to_float(abs(p_tilde / (root * dp)))
Exemplo n.º 5
0
def condition_number(n, root):
    r"""Compute the condition number of :math:`p(s)` at a root.

    When :math:`p(s) = (1 - 5s)^n + 2^{30} (1 - 3s)^n` is written in the
    Bernstein basis, we have :math:`\widetilde{p}(s) = (1 + 3s)^n +
    2^{30} (1 + s)^n`.
    """
    if not 0 <= root <= 1:
        raise ValueError("Expected root in unit interval.", root)
    p_tilde = (1 + 3 * root) ** n + RHS * (1 + root) ** n
    dp = -5 * n * (1 - 5 * root) ** (n - 1) - RHS * 3 * n * (1 - 3 * root) ** (
        n - 1
    )
    return plot_utils.to_float(abs(p_tilde / (root * dp)))
Exemplo n.º 6
0
def find_best_solution(n):
    """Finds :math:`1 + 2^{-31/n}` to highest precision."""
    highest = 500
    root = None
    counter = collections.Counter()
    for precision in range(100, highest + 20, 20):
        ctx = mpmath.MPContext()
        ctx.prec = precision

        value = 1 + ctx.root(0.5**31, n)
        if precision == highest:
            root = value
        value = plot_utils.to_float(value)
        counter[value] += 1

    if len(counter) != 1:
        raise ValueError("Expected only one value.")
    return root
Exemplo n.º 7
0
def main():
    ctx = mpmath.MPContext()
    ctx.prec = 500

    s0 = 1.0
    t0 = 1.0

    cond_nums = np.empty((24, ))
    rel_errors1 = np.empty((24, ))
    rel_errors2 = np.empty((24, ))
    for n in range(3, 49 + 2, 2):
        r = 0.5**n
        r_inv = 1.0 / r
        cond_num = kappa(r, ctx)

        # Compute the coefficients.
        coeffs1 = np.asfortranarray([[-2.0 - r, -2.0 - r, 6.0 - r],
                                     [2.0 + r_inv, r_inv, 2.0 + r_inv]])
        coeffs2 = np.asfortranarray([[-4.0, -4.0, 12.0],
                                     [5.0 + r_inv, -3.0 + r_inv, 5.0 + r_inv]])
        # Use Newton's method to find the intersection.
        iterates1 = newton_bezier.newton(s0, coeffs1, t0, coeffs2,
                                         newton_bezier.standard_residual)
        iterates2 = newton_bezier.newton(s0, coeffs1, t0, coeffs2,
                                         newton_bezier.compensated_residual)
        # Just keep the final iterate and discard the rest.
        s1, t1 = iterates1[-1]
        s2, t2 = iterates2[-1]
        # Compute the relative error in the 2-norm.
        sqrt_r = ctx.sqrt(r)
        alpha = 0.5 * (1 + sqrt_r)
        beta = 0.25 * (2 + sqrt_r)
        size = ctx.norm([alpha, beta], p=2)
        rel_error1 = ctx.norm([alpha - s1, beta - t1], p=2) / size
        rel_error2 = ctx.norm([alpha - s2, beta - t2], p=2) / size
        # Convert the errors to floats and store.
        cond_nums[(n - 3) // 2] = plot_utils.to_float(cond_num)
        rel_errors1[(n - 3) // 2] = plot_utils.to_float(rel_error1)
        rel_errors2[(n - 3) // 2] = plot_utils.to_float(rel_error2)

    # Make sure all of the non-compensated errors are non-zero and
    # at least one of the compensated errors is zero.
    if rel_errors1.min() <= 0.0:
        raise ValueError("Unexpected minimum error (non-compensated).")
    if rel_errors2.min() <= 0.0:
        raise ValueError("Unexpected minimum error (compensated).")

    figure = plt.figure()
    ax = figure.gca()
    # Add all of the non-compensated errors.
    ax.loglog(
        cond_nums,
        rel_errors1,
        marker="v",
        linestyle="none",
        color=plot_utils.BLUE,
        label="Standard",
    )
    # Add all of the compensated errors.
    ax.loglog(
        cond_nums,
        rel_errors2,
        marker="d",
        linestyle="none",
        color=plot_utils.GREEN,
        label="Compensated",
    )

    # Plot the lines of the a priori error bounds.
    min_x = 1.5
    max_x = 5.0e+32
    for coeff in (U, U**2):
        start_x = min_x
        start_y = coeff * start_x
        ax.loglog(
            [start_x, max_x],
            [start_y, coeff * max_x],
            color="black",
            alpha=ALPHA,
            zorder=1,
        )
    # Add the ``x = 1/U`` and ``x = 1/U^2`` vertical lines.
    min_y = 1e-18
    max_y = 5.0
    for x_val in (1.0 / U, 1.0 / U**2):
        ax.loglog(
            [x_val, x_val],
            [min_y, max_y],
            color="black",
            linestyle="dashed",
            alpha=ALPHA,
            zorder=1,
        )
    # Add the ``y = u`` and ``y = 1`` horizontal lines.
    for y_val in (U, 1.0):
        ax.loglog(
            [min_x, max_x],
            [y_val, y_val],
            color="black",
            linestyle="dashed",
            alpha=ALPHA,
            zorder=1,
        )

    # Set "nice" ticks.
    ax.set_xticks([10.0**n for n in range(4, 28 + 8, 8)])
    ax.set_yticks([10.0**n for n in range(-16, 0 + 4, 4)])
    # Set special ``xticks`` for ``1/u`` and ``1/u^2``.
    ax.set_xticks([1.0 / U, 1.0 / U**2], minor=True)
    ax.set_xticklabels([r"$1/\mathbf{u}$", r"$1/\mathbf{u}^2$"], minor=True)
    ax.tick_params(
        axis="x",
        which="minor",
        direction="out",
        top=1,
        bottom=0,
        labelbottom=0,
        labeltop=1,
    )
    # Set special ``yticks`` for ``u`` and ``1``.
    ax.set_yticks([U, 1.0], minor=True)
    ax.set_yticklabels([r"$\mathbf{u}$", "$1$"], minor=True)
    ax.tick_params(
        axis="y",
        which="minor",
        direction="out",
        left=0,
        right=1,
        labelleft=0,
        labelright=1,
    )
    # Label the axes.
    ax.set_xlabel("Condition Number", fontsize=plot_utils.TEXT_SIZE)
    ax.set_ylabel("Relative Forward Error", fontsize=plot_utils.TEXT_SIZE)
    # Make sure the ticks are sized appropriately.
    ax.tick_params(labelsize=plot_utils.TICK_SIZE)
    ax.tick_params(labelsize=plot_utils.TEXT_SIZE, which="minor")

    # Set axis limits.
    ax.set_xlim(min_x, max_x)
    ax.set_ylim(min_y, max_y)
    # Add the legend.
    ax.legend(
        loc="upper left",
        framealpha=1.0,
        frameon=True,
        fontsize=plot_utils.TEXT_SIZE,
    )

    figure.set_size_inches(6.0, 4.5)
    figure.subplots_adjust(left=0.11,
                           bottom=0.09,
                           right=0.96,
                           top=0.94,
                           wspace=0.2,
                           hspace=0.2)
    filename = "almost_tangent.pdf"
    path = plot_utils.get_path("compensated-newton", filename)
    figure.savefig(path)
    print("Saved {}".format(filename))
    plt.close(figure)