## modules
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

## Q1
a, b, y_0, n = 0, 10, 1, 10

## Q2
def euler_logistique(a,b,y_0,n,r,K):
    h = (b - a) / n
    t, y = [a], [y_0]
    for k in range(n):
        y.append(y[k] + h * r * y[k] * (1 - y[k] / K))
        t.append(t[k] + h)
    return t, y

## Q3
r, K = 0.5, 10

def f(t):
    return K * y_0 * np.exp(r * t) / (K + y_0 * (np.exp(r * t) - 1))

t,y = euler_logistique(a,b,y_0,n,r,K)
plt.plot(t,y,marker="+",label="Euler")

abs = np.linspace(a, b, 300)
plt.plot(abs, f(abs),label="f")

plt.legend(loc = "best") # optionnel
plt.show()



## Q4
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)

# tracé initial
n = 10
t, y = euler_logistique(a, b, y_0, n, r, K)
ligne_euler, = ax.plot(t, y, label="Euler")

abscisses = np.linspace(a, b, 300)
ax.plot(abscisses, [f(x) for x in abscisses], label="f")

ax.set_xlabel("t")
ax.set_ylabel("y")
ax.legend(loc="best")

# --- curseur ---
ax_slider = plt.axes([0.25, 0.1, 0.5, 0.03])
n_slider = Slider(ax_slider, "n", 2, 100, valinit=n, valstep=1)

def update(val):
    n = int(n_slider.val)
    t, y = euler_logistique(a, b, y_0, n, r, K)
    ligne_euler.set_data(t, y)
    ax.relim()
    ax.autoscale_view()
    fig.canvas.draw_idle()

n_slider.on_changed(update)
plt.show()

## Q5
def euler(F,a,b,y_0,n):
    t = [a]
    y = [y_0]
    h = (b-a)/n
    for k in range(n):
        t.append(t[k]+h)
        y.append(y[k]+h*F(t[k],y[k]))
    return (t,y)

## Q6
def F(t,y):
    return -5*np.sin(5*t)*np.exp(-t) - y

## Q7
a, b, y_0 = 0, 5, 1

def g(x):
    return np.cos(5*x)*np.exp(-x)

for n in [10,30,100]:
    t, y = euler(F,a,b,y_0,n)
    legende = "n = " + str(n) # redaction de la legende
    plt.plot(t,y,label=legende)

abscisses = np.linspace(a,b,500)
ord = [g(x) for x in abscisses] # ou ord = g(abscisses)
plt.plot(abscisses,ord,label="g")

plt.legend(loc = "best") # place les legendes a la meilleure place
plt.show()

## Q9
def heun(F,a,b,y_0,n):
    t = [a]
    y = [y_0]
    h = (b-a)/n
    for k in range(n):
        t.append(t[k]+h)
        p1 = F(t[k],y[k])
        p2 = F(t[k]+h,y[k]+h*p1)
        y.append(y[k]+h*(p1+p2)/2)
    return (t,y)

def rk4(F,a,b,y_0,n):
    t = [a]
    y = [y_0]
    h = (b-a)/n
    for k in range(n):
        t.append(t[k]+h)
        p1 = F(t[k],y[k])
        p2 = F(t[k]+h/2,y[k]+h*p1/2)
        p3 = F(t[k]+h/2,y[k]+h*p2/2)
        p4 = F(t[k]+h,y[k]+h*p3)
        y.append(y[k]+h*(p1+2*p2+2*p3+p4)/6)
    return (t,y)

## Q10
a, b, y_0 = 0, 5, 1

n = 50

t1, y1 = euler(F,a,b,y_0,n)
plt.plot(t1,y1,label="Euler")

t2, y2 = heun(F,a,b,y_0,n)
plt.plot(t2,y2,label="Heun")

t3, y3 = rk4(F,a,b,y_0,n)
plt.plot(t3,y3,label="RK4")

abscisses = np.linspace(a,b,500)
ord = [g(x) for x in abscisses]
plt.plot(abscisses,ord,label="g")

plt.legend(loc = "best") # place les legendes a la meilleure place
plt.show()

## Q11
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)

# tracé initial
n = 10
t1, y1 = euler(F,a,b,y_0,n)
t2, y2 = heun(F,a,b,y_0,n)
t3, y3 = rk4(F,a,b,y_0,n)

ligne_euler, = ax.plot(t1, y1, label="Euler")
ligne_heun, = ax.plot(t2, y2, label="Heun")
ligne_rk4, = ax.plot(t3, y3, label="RK4")

abscisses = np.linspace(a, b, 1000)
ax.plot(abscisses, g(abscisses), label="g")

ax.set_xlabel("t")
ax.set_ylabel("y")
ax.legend(loc="best")

# --- curseur ---
ax_slider = plt.axes([0.25, 0.1, 0.5, 0.03])
n_slider = Slider(ax_slider, "n", 10, 500, valinit=n, valstep=1)

def update(val):
    n = int(n_slider.val)
    t1, y1 = euler(F,a,b,y_0,n)
    t2, y2 = heun(F,a,b,y_0,n)
    t3, y3 = rk4(F,a,b,y_0,n)
    ligne_euler.set_data(t1, y1)
    ligne_heun.set_data(t2, y2)
    ligne_rk4.set_data(t3, y3)
    ax.relim()
    ax.autoscale_view()
    fig.canvas.draw_idle()

n_slider.on_changed(update)
plt.show()
































