import numpy as np
import matplotlib.pyplot as plt

## Les deux premiers exercices sont de la documentation (linspace, plot).
## np.linspace(start, stop, num=50, endpoint=True) : num points régulièrement
## espacés de start à stop (inclus si endpoint=True). start et stop sont
## obligatoires ; num et endpoint sont optionnels.


## Graphes de fonctions

def f(x):
    return (np.exp(x) + np.exp(-x)) / 2

def g(x):
    return x + np.sin(x)

def h(x):
    # h(0) = 0 par continuité (x * sin(1/x) -> 0)
    x = np.asarray(x, dtype=float)
    y = np.zeros_like(x)
    mask = x != 0
    y[mask] = x[mask] * np.sin(1 / x[mask])
    return y

# Graphe de f sur [-2, 2]
X = np.linspace(-2, 2, 400)
plt.figure()
plt.plot(X, f(X))
plt.axis("equal")
plt.grid()
plt.show()
# f est paire, croissante sur [0, +oo[, limites +oo en +/-oo (cosh).

# f et g sur [-5, 5]
X = np.linspace(-5, 5, 400)
plt.figure()
plt.plot(X, f(X), color="blue", linestyle="solid", label="f")
plt.plot(X, g(X), color="red", linestyle="dashed", label="g")
plt.xlim(-5, 5)
plt.ylim(-6, 10)
plt.legend()
plt.grid()
plt.show()

# h sur [-2, 2], puis zoom
X = np.linspace(-2, 2, 2000)
plt.figure()
plt.plot(X, h(X))
plt.xlim(-0.5, 0.5)
plt.ylim(-0.25, 0.25)
plt.grid()
plt.show()


## Courbes paramétrées (à exécuter telles quelles)

T = np.linspace(0, 100, 500)
X = T * np.cos(T)
Y = T * np.sin(T)
plt.figure()
plt.plot(X, Y)
plt.show()

T = np.linspace(0, 2 * np.pi, 500)
X = np.cos(T) * (1 - np.cos(T))
Y = np.sin(T) * (1 - np.cos(T))
plt.figure()
plt.plot(X, Y)
plt.show()
# Cardioïde.


## Conjecture : max de n**(1/n)

def phi(x):
    return x ** (1 / x)

X = np.linspace(1, 10, 400)
plt.figure()
plt.plot(X, phi(X))
plt.grid()
plt.show()
# Le maximum pour n entier est atteint en n = 3
# (phi(2) = sqrt(2) ~ 1.414, phi(3) ~ 1.442).


## tan, arctan et la bissectrice y = x

plt.figure()
X = np.linspace(-np.pi / 2 + 0.05, np.pi / 2 - 0.05, 400)
plt.plot(X, np.tan(X), label="tan")
X = np.linspace(-5, 5, 400)
plt.plot(X, np.arctan(X), label="arctan")
plt.plot(X, X, linestyle="dashed", label="y = x")
plt.ylim(-5, 5)
plt.legend()
plt.grid()
plt.show()


## Escalier / escargot

def escalier(f, n, a):
    X = [a]
    Y = [0]
    for k in range(n):
        X.append(X[-1])
        Y.append(f(X[-1]))
        X.append(Y[-1])
        Y.append(Y[-1])
    plt.plot(X, Y, color="red")

def f_sqrt(x):
    return np.sqrt(1 + x)

plt.figure("Suite récurrente")
X = np.linspace(-1, 3, 400)
plt.plot(X, 0 * X, color="black")
plt.plot(0 * X, X, color="black")
plt.plot(X, X, linestyle="dashed", color="green")
plt.plot(X, f_sqrt(X), color="blue")
escalier(f_sqrt, 15, 0)
plt.xlim(-1, 3)
plt.ylim(-1, 3)
plt.show()
# La suite est croissante et converge vers (1+sqrt(5))/2 (point fixe).
# Si a est déjà au-dessus du point fixe, elle est décroissante.

def f_inv(x):
    return 1 / (1 + x)

plt.figure("Suite récurrente")
X = np.linspace(-0.5, 2.5, 400)
plt.plot(X, 0 * X, color="black")
plt.plot(0 * X, X, color="black")
plt.plot(X, X, linestyle="dashed", color="green")
plt.plot(X, f_inv(X), color="blue")
escalier(f_inv, 20, 1)
plt.xlim(-0.5, 2.5)
plt.ylim(-0.5, 2.5)
plt.show()
# Oscillation autour du point fixe (racine de x^2+x-1=0), convergence.
