##TD 9 dichotomie
def f(x):
    return x**2-2
    
f_math=lambda x:x**2 -2 
print('méthode tradi ',f(3), '\n méthode rapide',f_math(3))

import numpy as np
import matplotlib.pyplot as plt
##Q3
g=lambda x,k:x+np.log(x)-k #import numpy as np
print(g(1,1))
#méthode classique 
def dicho(a,b,f):
    """ Algorithme de recherche de 0 par dichotomie sur l'intervalle : [a,b] de f
    """
    e=1e-8
    compt=1
    while (abs(b-a)> e) and compt<4 :
        c=(a+b)/2.
        if f(a,k)*f(c,k)<0:
            b=c
        else:
            a=c
        compt+=1
        print(c)  
k=10
dicho(0.001,10,g)
##
x=np.linspace(0.01,10,100)
y=g(x,k)
plt.plot(x,y)
plt.axhline(color="black") 
plt.grid()
plt.show()
##
#Q6
def dicho2(a,b,f):
    N=[]
    x=[]
    e=1e-8
    compt=0
    while (abs(b-a)> e) or compt<100 :
        c=(a+b)/2.
        if f(a,k)*f(c,k)<0:
            b=c
        else:
            a=c
        compt+=1
        N.append(compt)#on cree la liste des coups
        x.append(c)#on crée la liste des xi  
    return x,N
    
N=dicho2(0.001,10,g)
plt.figure(2)
plt.plot(N[1],N[0],'r+-')
plt.xlabel('$coups$')
plt.ylabel('$x_i$')

##newton
def f(x):
    return x+np.log(x)-10
    
def deriv(x,f):
    h=1e-3
    return (f(x+h)-f(x))/h 

def newton(a,b,xo,f):
    liste=[]
    while abs(f(xo))>1e-15:  
        x=xo-f(xo)/deriv(xo,f)
        xo=x
    print(x)

newton(0.001,10,5,f)

##Q7: concentration Newton
T = np.array([0,7,18,27,37,56,102])
C = np.array([34.83,32.14,28.47,25.74,23.14,18.54,11.04])
Temps = np.linspace(0,110,100)
g = lambda t: 34.83*np.exp(-0.011214*t)
Y = g(Temps)
plt.title('comparaison de la cinétique d\'ordre 1 avec k = 0.03 avec les points expérimentaux ', fontsize=20)
plt.plot(T,C,'o')
plt.plot(Temps,Y,'black')
plt.grid()
plt.xlabel('temps (s)', fontsize=20)
plt.ylabel('concentration (mol/L)', fontsize=20)
plt.show()

## Question 7 (méthode de Newton)
f = lambda x : sum((C-C[0]*np.exp(-T*x))**2)
df = lambda x : 2 * C[0] * sum(T * (C-C[0]*np.exp(-x*T)) * np.exp(-x*T))
ddf = lambda x : 2*C[0] * sum(T**2 * (2*C[0]*np.exp(-x*T) - C) * np.exp(-x*T))

def newton(f,g,u,n):
    for i in range(n):
        u = u - f(u)/g(u)
    print("f' = " + str(df(u)))
    return u

"""
il faut chercher le zéro de f’sur I et si on utilise, il faut calculer f’’.
"""    
def solutionNewton(u,n):
    return newton(df,ddf,u,n)
    
print(solutionNewton(0.1,10))
print(solutionNewton(0.1,50))
print(solutionNewton(0.1,100))
print(solutionNewton(0.02,10))
print(solutionNewton(0.02,50))
print(solutionNewton(0.02,100))
## Tracé de la dérivé de F
import numpy as np
T = np.array([0,7,18,27,37,56,102])
C = np.array([34.83,32.14,28.47,25.74,23.14,18.54,11.04])
f = lambda x : sum((C-C[0]*np.exp(-T*x))**2)
df = lambda x : 2 * C[0] * sum(T * (C-C[0]*np.exp(-x*T)) * np.exp(-x*T))
dfv = np.vectorize(df) # Vectorisation de df pour l'appliquer à un tableau
ddf = lambda x : 2*C[0] * sum(T**2 * (2*C[0]*np.exp(-x*T) - C) * np.exp(-x*T))
ddfv = np.vectorize(ddf)

plt.figure(3)
X1 = np.linspace(0,0.1,100) # tableau des Abcisses
Y = dfv(X1)
plt.subplot(121)
plt.title('tracé de la dérivée de f',fontsize=20)
plt.plot(X1,Y, linewidth=4)
plt.grid()
plt.show()

X2 = np.linspace(0.02,0.04,100)
Z = ddfv(X2)
plt.subplot(122)
plt.title('tracé de la dérivée seconde de f',fontsize=20)
plt.plot(X2,Z,linewidth=4)
plt.grid()
plt.show()

##Q9
"""	On constate que si on prend comme premier terme de la suite 0.1, la méthode de Newton diverge.
Si u0 = 0.02, la méthode de Newton converge et kmin = 0.0112140333598
Explications supplémentaires : 
f’’ s’annule pour k = 0.028 et f’ est strictement décroissante pour 0,028 ≤ x ≤0.1 ce qui « fait partir Newton dans les choux » !
"""

##Q10
"""Pour trouver le zéro de f’ il faut que f’ soit continue sur l’intervalle d’étude [a,b] et f’(a).f’(b) < 0.
On constate avec le graphe de l’énoncé que f est décroissante autour de 0.005 et croissante autour de 0.02 donc l’intervalle [0.005,0.02] convient (on peut assurément encore resserrer l’intervalle).
"""


