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

from plot_helpers import CO, bold_ticks


def fig6_8():
    # Integrate f(x) over [a, b] using midpoint, trap, and simpson's rule
    #
    # Inputs:
    #       a = left endpoint of interval
    #       b = right endpoint of interval
    #       n = number of subintervals
    #

    a = 0
    b = 1
    exact = (np.exp(3) - 1) / 3

    # composite midpoint
    intervm = np.array([10, 20, 40, 80, 160, 320, 640])
    nkm = len(intervm)
    M = np.zeros(nkm)
    errm = np.zeros(nkm)
    for k in range(nkm):
        n = int(intervm[k])
        M[k] = midpt(a, b, n)
        errm[k] = abs(exact - M[k])
        # print(' n = ...')

    # composite trap
    intervt = np.array([10, 20, 40, 80, 160, 320, 640])
    nkt = len(intervt)
    T = np.zeros(nkt)
    errt = np.zeros(nkt)
    for k in range(nkt):
        n = int(intervt[k])
        T[k] = trap(a, b, n)
        errt[k] = abs(exact - T[k])
        # print(' n = ...')

    # composite simpson
    intervs = np.array([10, 20, 40, 80, 160, 320, 640])
    nks = len(intervs)
    S = np.zeros(nks)
    errs = np.zeros(nks)
    for k in range(nks):
        n = int(intervs[k])
        S[k] = simp(a, b, n)
        errs[k] = abs(exact - S[k])
        # print(' n = ...')

    # plot error using loglog plot
    plt.close("all")
    # get(gcf)
    fig, ax = plt.subplots(figsize=(8.8, 3.3))
    fig.subplots_adjust(left=0.10, right=0.98, bottom=0.22, top=0.98)
    ax.set_prop_cycle(cycler(color=CO))

    ax.loglog(
        intervt,
        errt,
        "--o",
        color=[0, 0.5, 0],
        markersize=8,
        linewidth=1.6,
    )
    ax.loglog(intervm, errm, "--db", markersize=8, linewidth=1.6)
    ax.loglog(intervs, errs, "--*r", markersize=8, linewidth=1.6)
    ax.grid(True)
    ax.set_xlabel("n-axis")
    ax.set_ylabel("Error")
    ax.legend(
        [" Trap", " Midpt", " Simp"],
        loc="lower left",
        prop={"size": 14, "weight": "bold"},
    )
    bold_ticks(ax, 14)
    plt.show()

    # plt.savefig('/Users/mark/Desktop/mts.eps')


def f(x):
    y = np.exp(3 * x)
    return y


### composite simpson: n = number of subintervals
def simp(a, b, n):
    xd = np.linspace(a, b, n + 1)
    h = xd[1] - xd[0]
    s = f(xd[0])
    ff2 = 0.0
    for j in range(1, n, 2):
        ff2 = f(xd[j + 1])
        s = s + 4 * f(xd[j]) + 2 * ff2
    s = h * (s - ff2) / 3
    return s


### composite trap: n = number of subintervals
def trap(a, b, n):
    xd = np.linspace(a, b, n + 1)
    h = xd[1] - xd[0]
    s = 0.5 * f(xd[0])
    for j in range(1, n):
        s = s + f(xd[j])
    s = h * (s + 0.5 * f(xd[n]))
    return s


### composite midpoint: n = number of subintervals
def midpt(a, b, n):
    xd = np.linspace(a, b, n + 1)
    h = xd[1] - xd[0]
    s = 0.0
    for j in range(n):
        s = s + f(xd[j] + 0.5 * h)
    s = h * s
    return s


if __name__ == "__main__":
    fig6_8()
