import numpy as np
import matplotlib.pyplot as plt

def dydt(t, y):
    return -2 * y

def rk4_step(f, t, y, h):
    k1 = f(t, y)
    k2 = f(t + h/2, y + h*k1/2)
    k3 = f(t + h/2, y + h*k2/2)
    k4 = f(t + h, y + h*k3)
    return y + h * (k1 + 2*k2 + 2*k3 + k4) / 6

def rk4_solver(f, t_span, y0, t_eval):
    t0, tf = t_span
    h = t_eval[1] - t_eval[0] 
    y_values = [y0]  
    t_values = [t0]  
    
    y = y0
    t = t0
    for t_next in t_eval[1:]:
        y = rk4_step(f, t, y, h)
        y_values.append(y)
        t = t_next
    
    return np.array(t_eval), np.array(y_values)

y0 = 1
t_span = (0, 5)
t_eval = np.linspace(0, 5, 100)

t_rk4, numerical_solution_rk4 = rk4_solver(dydt, t_span, y0, t_eval)

def analytical_solution(t):
    return np.exp(-2 * t)

analytical_solution_vals = analytical_solution(t_eval)

error_rk4 = np.abs(numerical_solution_rk4 - analytical_solution_vals)

plt.figure(figsize=(10, 6))  

plt.subplot(2, 1, 1) 
plt.plot(t_rk4, numerical_solution_rk4, label='Numerical Solution (RK4)', linestyle='--')
plt.plot(t_eval, analytical_solution_vals, label='Analytical Solution', linestyle='-')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('Comparison of Numerical and Analytical Solutions')
plt.legend()

plt.subplot(2, 1, 2) 
plt.plot(t_eval, error_rk4, label='Error', color='red')
plt.xlabel('t')
plt.ylabel('Error')
plt.title('Error between Numerical and Analytical Solutions')
plt.tight_layout()

plt.show()
