import math
import numpy as np
import matplotlib.pyplot as plt
from cycler import cycler


def fig2_13():
    #  Solve  f(x) = 0  using bisection, Newton, and secant

    # Solution of  exp(-x)-(2+x) = 0  to 20 digits:
    # xe=-0.4428544010023885831;

    tol = 10 ** (-12)
    a0 = -2
    b0 = 0

    # bisection procedure
    a = a0
    b = b0
    mid = 0.5 * (a + b)
    tolB = 10 ** (-3)
    err = 10 * tolB
    it = 0
    errB = []
    while err > tolB:
        old = mid
        fmid = f(mid)
        if f(a) * fmid < 0:
            b = mid
        elif f(b) * fmid < 0:
            a = mid
        else:
            break
        mid = 0.5 * (a + b)
        it = it + 1
        err = abs((mid - old) / mid)
        errB.append(err)
    print(it)

    # secant procedure
    x = b0
    X = a0
    k = 0
    err = 10 * tol
    itS = []
    errS = []
    while err > tol:
        k = k + 1
        z = f(x) * (x - X) / (f(x) - f(X))
        X = x
        x = x - z
        err = abs(z / x)
        itS.append(k + 1)
        errS.append(abs(z / x))
    print(k)

    # newton
    x = b0
    err = 10 * tol
    k = 0
    errN = []
    while err > tol:
        k = k + 1
        z = f(x) / df(x)
        x = x - z
        err = abs(z / x)
        errN.append(err)
    print(k)

    plt.close("all")
    # get(gcf)
    fig, ax = plt.subplots(
        figsize=(658 / 100, 230 / 100), dpi=100, constrained_layout=True
    )
    co = [
        (0, 0, 1),
        (0, 0.5, 0),
        (1, 0, 0),
        (0, 0.75, 0.75),
        (0.75, 0, 0.75),
        (0.75, 0.75, 0),
        (0.25, 0.25, 0.25),
    ]
    plt.rcParams["axes.prop_cycle"] = cycler(color=co)

    # plot error
    ax.semilogy(np.arange(1, len(errB) + 1), errB, "--sk", linewidth=1.5, markersize=8)
    ax.semilogy(itS, errS, "--*b", linewidth=1.5, markersize=8)
    ax.semilogy(np.arange(1, len(errN) + 1), errN, "--or", linewidth=1.5, markersize=8)

    ax.legend(
        [" Bisect", " Secant", " Newton"],
        loc="lower right",
        prop={"weight": "bold", "size": 14},
    )
    ax.axis([1, 12, 1e-16, 10])
    ax.set_yticks([1e-16, 1e-12, 1e-8, 1e-4, 1])
    ax.set_xlabel("k")
    ax.set_ylabel("Error")
    ax.grid(True)
    for spine in ax.spines.values():
        spine.set_visible(True)
    ax.tick_params(labelsize=14)
    for label in ax.get_xticklabels() + ax.get_yticklabels():
        label.set_fontweight("bold")
    ax.xaxis.label.set_fontsize(14)
    ax.yaxis.label.set_fontsize(14)
    ax.xaxis.label.set_fontweight("bold")
    ax.yaxis.label.set_fontweight("bold")

    # fig.savefig('/Users/mark/Desktop/compar.eps')
    plt.show()


def f(x):
    g = math.exp(-x) - 2 - x
    return g


def df(x):
    g = -math.exp(-x) - 1
    return g


if __name__ == "__main__":
    fig2_13()
