import numpy as np
from numpy.polynomial import Polynomial

#Exercice 7

#Définition des polynômes comme liste de leurs coefficients selon les puissances croissantes
P=Polynomial([8,4,-3,0,1])
Q=Polynomial([3,2,-4,1])
R=Polynomial([3,-6,0,0,1])

#a. Valeur de P(2)
print(P(2))

#b.Racines de Q
print(Q.roots())

#c. Graphe de R
L=np.linspace(-1,1,100)
plt.plot(L,R(L))
plt.show()

#d. Calcul du polynôme (P+Q')R''
S=(P+Q.deriv())*R.deriv(2)
#Coefficient de S selon X^3
print(S.coef[3])

#e. Division euclidienne de PQ par R, liste des coefficients du reste :
print(((P*Q)%R).coef)

#Exercice 8

#1. Définition du produit scalaire, méthode 1
def ps(P,Q):
    R=(P*Q).integ()
    return(R(1)-R(-1))

#1. Définition du produit scalaire, méthode 2
import scipy.integrate as integr
def psbis(P,Q):
    return(integr.quad(P*Q,-1,1)[0])

#2. Définition des polynômes Qn

from math import factorial
def Q(n):
    p=Polynomial([-1,0,1])**n
    pn=p.deriv(n)
    return(1/(2**n*factorial(n))*pn)

#3. Les Qn forment une base orthogonale
for k in range(5):
    for l in range(5):
        print(k,l,ps(Q(k),Q(l)))
#L'utilisation de psbis donnerait lieu à des valeurs approchées.

#On conjecture que ||Q_n|| est de norme 2/(2n+1)

#4. Graphe des premiers polynômes

Lt=np.linspace(-1,1,201)
plt.plot(Lt,Q(1)(Lt),Lt,Q(2)(Lt),Lt,Q(3)(Lt),Lt,Q(4)(Lt),Lt,Q(5)(Lt))
plt.show()

#5. Un projeté orthogonal

A=Polynomial([-3,5,6,0,-3,0,0,1])

#On divise Q_n par sa norme pour obtenir une base orthonormée :
def R(n):
    N=(2/(2*n+1))**0.5
    return(1/N*Q(n))

#Calcul du projeté orthogonal :
pA=sum([ps(A,R(k))*R(k) for k in range(5)])
#Calcul de la distance :
print(ps(A-pA,A-pA)**0.5)