#Corrigé du TP d'analyse

import numpy as np
import scipy.optimize as resol
import scipy.integrate as integr
import matplotlib.pyplot as plt


## Exercice 1

def f(x): return(np.exp(-x**2))
def g(x): return(np.arctan(x))

# a. Tracé du graphe de f et g

Lx=np.linspace(0,2,51)
Lf=[f(x) for x in Lx]
Lg=[g(x) for x in Lx]
plt.plot(Lx,Lf,Lx,Lg)
plt.grid()
plt.show()

# b. Coordonnées du point d'intersection

def h(x): return(f(x)-g(x))

b=resol.fsolve(h,1)
print(b)

# c. Aire délimitée par les deux courbes et l'axe des ordonnées

A=integr.quad(h,0,b)[0]
print(A)

## Exercice 2

def f(x):
    def g(t):
        return(np.log(x**2-2*x*np.cos(t)+1))
    return(integr.quad(g,0,np.pi)[0])

def h(x):
    return(2*np.pi*np.log(x))

L=np.linspace(0.1,10,100)
Lf=[f(x) for x in L]
Lh=[h(x) for x in L]
plt.plot(L,Lf,L,Lh)
plt.grid()
plt.show()

#On conjecture que f(x)=0 si 0<x<=1, et f(x)=2 pi ln(x) pour x>1.

## Exercice 3

from math import factorial

La=[1]
for n in range(1,101):
    S=0
    for k in range(1,n+1):
        S+=La[n-k]/factorial(k)
    La.append(-S/2)

def f(x):
    v=0
    for n in range(101):
        v+=La[n]*x**n
    return(v)

def g(x):
    return(2/(1+np.exp(x)))

L=np.linspace(-1,1,200)
Lf=[f(x) for x in L]
Lg=[g(x)+0.1 for x in L]
#En rajoutant 0.1 à g, on observera mieux le fait les deux graophes se superposent.

plt.plot(L,Lf,'r',L,Lg,'b')
plt.grid()
plt.show()

## Exercice 4

def I(n):
    def f(t):
        return(t**2/((1+t**4)**n))
    return(integr.quad(f,0,np.inf)[0])

for n in range(1,7):
    print(n*(1-I(n+1)/I(n)))

# On conjecture que cette suite vaut 3/4, autrement dit que
#I(n+1)=(1- 3/(4n)) * I(n) pour tout n.

L=[n for n in range(3,21)]
L1=[np.log(n) for n in L]
L2=[np.log(I(n)) for n in L]
plt.plot(L1,L2)
plt.show()

#On conjecture une relation de la forme ln(I(n)) ~ -a ln(n)+b
# d'où ln(I(n)/n**(-a)) --> b
# et donc I(n) ~ e^b/n^a
# la valeur approchée de -a est la pente entre, par exemple, les points d'abscisse 10 et 20.

print((np.log(I(20))-np.log(I(10)))/(np.log(20)-np.log(10)))

## Exercice 5

def u(n):
    def f(x):
        return(sum([x**k for k in range(1,n+1)])-1)
    return(resol.fsolve(f,1))

X=range(1,51)
Y=[u(n) for n in X]
plt.plot(X,Y,'*')
plt.show()

#On conjecture que cette suite est décroissante et tend vers 1/2

X=range(1,31)
Z=[2**n*(u(n)-1/2) for n in X]
plt.plot(X,Z,'*')
plt.show()

#On conjecture que cette suite converge vers 1/4 (et donc que u_n=1/2+1/2**(n+2)+o(1/2**n)).
#Attention, avec de trop grandes valeurs de n, le comportement graphique devient irrégulier, du fait d'erreurs d'arrondi

## Exercice 6

def A(n,t):
    S=0
    for k in range(1,n+1):
        S+=np.sin(k*t)/k
    return(S)

L=np.linspace(-10,10,101)
for n in range(1,6):
    Ly=[A(n,x) for x in L]
    plt.plot(L,Ly)
plt.grid()
plt.show()

#On observe que A_n se rapporche d'un signal en dents de scie.

def f(t):
    return(np.sin(np.pi*t)/t)
I=integr.quad(f,0,1)[0]

print(A(1000,np.pi/1000),I)


## Exercice 7

def I(n):
    def f(t):
        return(((1-t)/(1-t**n))**0.5)
    return(integr.quad(f,0,1)[0])

X=range(1,101)
Y=[I(n) for n in X]
plt.plot(X,Y,'*')
plt.show()

#On conjecture que la suite (I(n)) converge. La valeur I(500) (qui vaut environ 0.6667) nous convainc que la limite est 2/3

l=2/3

X=range(1,501)
Z=[n**1.5*(I(n)-l) for n in X]
plt.plot(X,Z,'*')
plt.show()

#On conjecture que cette suite converge vers une limite c légèrement supérieure à 3/4. On conjecture un développement asymtotique de la forme I(n) = 2/3 + c/n**(3/2) + o(1/n**(3/2))



## Exercice 8

def f(x):
    def g(t):
        return(1/np.log(t))
    return(integr.quad(g,x,x**2)[0])

L=np.linspace(0.1,3,100)
Lf=[f(x) for x in L]
plt.plot(L,Lf)
plt.show()

M=np.linspace(0.9,1.1,100)
Mg=[np.exp(f(x)) for x in M]
plt.plot(M,Mg)
plt.show()

#On conjecture que exp(f(x)) tend vers 2 quand x tend vers 1, donc que f(x) tend vers ln(2).

##Exercice 9

from math import factorial

def a(n):
    def f(x):
        return(np.exp(-x)*sum([x**k/factorial(k) for k in range(n+1)])-0.5)
    return(resol.fsolve(f,n))
a=np.vectorize(a)

L=np.arange(0,21,1)
La=[a(x) for x in L]
plt.plot(L,La,L,L,L,L+1)
plt.show()
#On conjecture que n<a_n<n+1 pour tout n

Lb=[3*(a(x)-x) for x in L]
plt.plot(L,Lb)
plt.show()
#On conjecture que cette suite tend vers 2, et donc qua a_n=n+2/3+o(1)

def f(n,x):
    S=sum([x**k/factorial(k) for k in range(n+1)])
    return(np.exp(-x)*S)

def g(n,x):
    def h(t):
        return(t**n/factorial(n)*np.exp(-t))
    I=integr.quad(h,x,np.inf)
    return(I[0])

L=np.linspace(0,5)
for n in [0,1,3,8]:
    Lf=[f(n,x)+0.1 for x in L]
    Lg=[g(n,x) for x in L]
    #J'ai ajouté 0.1 à f pour décaler son graphe vers le haut et mieux voir que f=g
    plt.plot(L,Lf,'r',L,Lg,'b')
plt.show()