IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Calcul formel en Python : les polynômes d'interpolation de Lagrange vus comme des vecteurs,
Un billet blog de Denis Hulo

Le , par User

0PARTAGES


I. Introduction

D'après Wikipedia, en algèbre linéaire, un espace vectoriel est un ensemble d'objets, appelés vecteurs, que l'on peut additionner entre eux, et que l'on peut multiplier par un scalaire (pour les étirer ou les rétrécir, les tourner, etc.).

On va d'abord montrer que l'ensemble des polynômes pouvant être construits sur la base des polynômes de Lagrange (l0, l1, …, ln) constitue un espace vectoriel.

Dans un second temps, on va représenter les polynômes d'interpolation de Lagrange à l'aide d'une classe en Python, puis définir les opérations d'addition entre ces vecteurs et de multiplication par un scalaire en utilisant la surcharge d'opérateur.

Enfin, on va tester le code Python en effectuant différentes opérations sur ces nouveaux objets comme on le ferait sur des vecteurs.

II. Espace vectoriel


II-A. Définition

Soit K un corps commutatif, comme le corps commutatif des rationnels, celui, , des réels ou celui, , des complexes (on parlera dans ces cas d'espace vectoriel rationnel, réel ou complexe).

D'après Wikipedia, un espace vectoriel sur K, est un ensemble E, dont les éléments sont appelés vecteurs, muni de deux lois :

  • une loi de composition interne « + » : E2E, appelée addition ou somme vectorielle ;
  • une loi de composition externe à gauche « • » : K × EE, appelée multiplication par un scalaire.


Une loi de composition interne est donc une application qui, à deux éléments d'un ensemble E, associe un élément de E, comme la multiplication ou l'addition dans l'ensemble des naturels.

Contrairement à une loi de composition interne, une loi de composition externe fait intervenir des éléments de l’extérieur, ici un scalaire dans K.

On admettra sans les démontrer les propriétés suivantes :

  • La loi « + » est commutative, associative, admet un élément neutre et tout élément de cette espace possède un opposé.
  • La loi « • » est distributive par rapport à la loi « + », vérifie une associativité mixte et admet un élément neutre à gauche.


II-B. Base d'un espace vectoriel


En algèbre linéaire, une base d'un espace vectoriel V est une famille de vecteurs de V linéairement indépendants et dont tout vecteur de V est combinaison linéaire.

Autrement dit, une base de V est une famille libre de vecteurs de V qui engendre V.

III. Polynômes d'interpolation de Lagrange

Soit n + 1 points (x0 ,y0) , … , (xn , yn) (avec les xi des réels distincts deux à deux).

Le polynôme d'interpolation de Lagrange de degré au plus n qui passe par ces points est défini par :



III-A. Espace ℝn[X] des polynômes


L étant une combinaison linéaire de polynômes de degré n, il est de degré au plus n et appartient donc à l'ensemble n[X].

Quel que soit le polynôme P appartenant à n[X], on peut également écrire :



Proposition :

Étant donné n + 1 réels distincts x0, …, xn, l'ensemble des polynômes que l'on peut construire avec la famille de polynômes (l0, l1, …, ln) constitue un espace vectoriel muni de deux lois :

  • une loi de composition interne « + », appelée addition ou somme vectorielle ;
  • une loi de composition externe à gauche « • », appelée multiplication par un scalaire.


Décrivons maintenant pour le vérifier les opérations pouvant être réalisées sur ces vecteurs.

III-A-1. Addition de polynômes

Soit deux polynômes d'interpolation de Lagrange P et Q construits avec la même famille de polynômes (l0, l1, …, ln) :



L'addition de ces deux polynômes donne :



On obtient donc un nouveau polynôme d'interpolation de Lagrange construit avec la même famille de polynômes (l0, l1, …, ln) et appartenant au même espace n[X].

Cette addition est donc bien une loi de composition interne dans cet espace vectoriel.

III-A-2. Multiplication d'un polynôme par un scalaire

La multiplication de P(X) par un scalaire s donne :



On obtient donc un nouveau polynôme d'interpolation de Lagrange construit avec la même famille de polynômes (l0, l1, …, ln) et appartenant au même espace.

Cette opération est donc bien une loi de composition externe dans cet espace vectoriel.

Ces deux opérations vérifient également les propriétés citées plus haut.

III-B. Base de polynômes

On se donne à nouveau n + 1 réels distincts x0, …, xn. Pour tout polynôme P appartenant à un espace n[X] des polynômes, si on pose yi = P(xi), P étant le polynôme d'interpolation correspondant aux points, il est égal au polynôme L défini précédemment.

On a donc :



Et donc (l0, l1, …, ln) forme une famille génératrice de n[X] et son cardinal (égal à n + 1) est égal à la dimension de l'espace.

Par exemple, en choisissant P = 1 ou P = X, on obtient :



On peut remarquer également que le polynôme nul P = 0 est tel que :



Cela implique nécessairement que :



On en déduit que cette famille génératrice (l0, l1, …, ln) est également libre, et par conséquent c'est une base de l'espace des polynômes qu'elle engendre.

Cette famille forme en fait une base orthonormée de n[X].

Si vous souhaitez avoir plus d'information sur le sujet je vous invite à consulter la page Wikipedia Interpolation lagrangienne.

IV. Implémentation en Python

Ces polynômes peuvent donc être vus comme des vecteurs sur lesquels on peut réaliser les opérations d'addition et de multiplication par un scalaire.

On va maintenant représenter les polynômes d'interpolation de Lagrange en Python à l'aide d'une classe, puis définir ces opérations en utilisant la surcharge d'opérateur.

IV-A. Création de la classe Polynome_lagrange

Pour définir ces polynômes en Python et pouvoir réaliser des opérations entre eux, il nous faut donc créer une classe Polynome_lagrange.


Sa méthode constructeur __init__() va nous permettre de définir les listes de valeurs x et y du polynôme d'interpolation de Lagrange au moment de créer l'objet :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np 
  
class Polynome_lagrange: 
  
    def __init__(self, x, y): 
        # méthode constructeur de la classe 
  
        # on définit la liste de valeurs en x permettant d'obtenir la famille de polynômes (l0, l1, ..., ln) représentant une base dans ℝn[X] 
        self.x = x 
  
        # on définit le tableau de valeurs en y représentant les coordonnées du vecteur (tableau numpy) 
        self.y = np.array(y) 
  
  
    def __str__(self): 
	...

En python, les tableaux de la librairie numpy représentent également des vecteurs sur lesquels on peut réaliser les mêmes opérations (addition, multiplication par un scalaire, etc.) :

La méthode __str__ permet d'afficher un polynôme sous la forme y0∙L0(X) + y1∙L1(X) + y2∙L2(X).

La classe comporte également deux autres méthodes espace() et base() permettant de connaître l'espace vectoriel du polynôme et sa base.

Pour tester ces méthodes, nous ajoutons ces quelques lignes au module :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
# création de l'objet Polynome_lagrange : 1∙L0(X) + 2∙L1(X) + 5∙L2(X) 
p = Polynome_lagrange(x=[0, 1, 2], y=[1, 2, 5])  
  
print(p) # affiche l'expression du polynôme 
  
print() 
  
# affiche l'appartenance de p à son espace vectoriel 
print("p ∈ " + p.espace() + ", Base = " + p.base())

Le code affiche :

1∙L0(X) + 2∙L1(X) + 5∙L2(X)

p ∈ ℝ2[X], Base = (L0, L1, L2), x = [0, 1, 2]


IV-A-1. Addition de deux polynômes

Pour surcharger l'opérateur « + » et pouvoir ainsi réaliser l'addition de 2 polynômes de même base, nous devons ajouter une méthode __add __ () à la classe :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Polynome_lagrange: 
    ...  
    def __add__(self, other): 
        # méthode permettant de redéfinir l'opérateur « + » pour 2 polynômes d'interpolation de Lagrange ou 2 vecteurs 
        # (y0*L0(X) + ... + yn*Ln(X)) + (z0*L0(X) + ... + zn*Ln(X)) = (y0 + z0)*L0(X) + ... + (yn + zn)*Ln(X) 
  
        # si les 2 vecteurs self et other ont la même base 
        if self.x==other.x: 
  
            # addition des 2 vecteurs self.y et other.y (2 tableaux numpy) 
            y = self.y + other.y 
  
            # renvoie le polynômes résultat de l'addition des 2 polynômes self et other 
            return Polynome_lagrange(self.x, y) 
  
        else: # sinon 
  
            print("Les 2 polynômes n'ont pas la même base !")

Cette méthode permet donc de redéfinir l'opération « + » pour les polynômes de même base en les additionnant comme des vecteurs d'un même espace.

Pour tester l'opérateur d'addition portant sur 2 objets de la classe Polynome_lagrange, nous ajoutons ces lignes de code :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# création du 1er objet de la classe Polynome_lagrange 
p1 = Polynome_lagrange(x=[0, 1, 2], y=[0, 1, 4]) 
  
# création du 2e objet de la classe Polynome_lagrange 
p2 = Polynome_lagrange(x=[0, 1, 2], y=[1, 2, 5]) 
  
# affiche l'expression des polynômes p1 et p2 
print("p1 = " + str(p1)) 
print("p2 = " + str(p2)) 
  
print() 
  
# affiche l'appartenance de p1 et p2 à son espace vectoriel : R2[X], Base = [L0, L1, L2], x = [0, 1, 2] 
print("p1 ∈ " + p1.espace() + ", Base = " + p1.base()) 
print("p2 ∈ " + p1.espace() + ", Base = " + p2.base()) 
  
print() 
  
print("p = p1 + p2") 
  
# addition des 2 polynômes 
p = p1 + p2 
  
print() 
  
# affiche le résultat de l'addition 
print("p = " + str(p)) 
print() 
  
# affiche l'appartenance de p à son espace vectoriel 
print("p ∈ " + p.espace() + ", Base = " + p.base())

Le code affiche :

p1 = 0∙L0(X) + 1∙L1(X) + 4∙L2(X)
p2 = 1∙L0(X) + 2∙L1(X) + 5∙L2(X)

p1 ∈ ℝ2[X], Base = (L0, L1, L2), x = [0, 1, 2]
p2 ∈ ℝ2[X], Base = (L0, L1, L2), x = [0, 1, 2]

p = p1 + p2

p = 1∙L0(X) + 3∙L1(X) + 9∙L2(X)

p ∈ ℝ2[X], Base = (L0, L1, L2), x = [0, 1, 2]


IV-A-2. Multiplication d'un polynôme par un scalaire

Pour réaliser la multiplication d'un objet Polynome_lagrange par un scalaire, on va ajouter une méthode __mul __ () qui va permettre de surcharger l'opérateur « * » :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
class Polynome_lagrange: 
    ...  
    def __mul__(self, s): 
        # méthode permettant de multiplier le polynôme self par un scalaire 
        # : s*(y0*L0(X) + ... + yn*Ln(X)) = s*y0*L0(X) + ... + s*yn*Ln(X) 
  
        # multiplication du vecteur self.y par le scalaire s 
        y = s*self.y 
  
        # renvoie le polynôme d'interpolation de Lagrange résultat de la multiplication de self par le scalaire s 
        return Polynome_lagrange(self.x, y)

Le scalaire s est passé comme deuxième argument à la fonction car le premier argument doit obligatoirement être un objet de la classe.

Pour tester l'opérateur de multiplication d'un objet de la classe Polynome_lagrange par un scalaire s, nous ajoutons maintenant ces lignes :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# création de l'objet de la classe Polynome_lagrange : 
p1 = Polynome_lagrange(x=[0, 1, 2], y=[1, 2, 5]) 
  
# affiche l'expression du polynôme p1 
print("p1 = " + str(p1)) 
  
print() 
  
# affiche l'appartenance de p1 à son espace vectoriel 
print("p1 ∈ " + p1.espace() + ", Base = " + p1.base()) 
  
print() 
  
# définition du scalaire s 
s = 2 
  
print("s = " + str(s)) 
  
print() 
  
print("p = p1*s ") 
  
# multiplication du polynôme p1 par le scalaire s 
p = p1*s 
  
print() 
  
# affiche le résultat de la multiplication de p1 par s 
print("p = " + str(p)) 
print() 
  
# affiche l'appartenance de p à son espace vectoriel 
print("p ∈ " + p.espace() + ", Base = " + p.base())

Le code affiche :

p1 = 1∙L0(X) + 2∙L1(X) + 5∙L2(X)

p1 ∈ ℝ2[X], Base = (L0, L1, L2), x = [0, 1, 2]

s = 2

p = p1*s

p = 2∙L0(X) + 4∙L1(X) + 10∙L2(X)

p ∈ ℝ2[X], Base = (L0, L1, L2), x = [0, 1, 2]


On peut également imaginer d'effectuer la somme, la moyenne ou toute combinaison linéaire de vecteurs de la même base pour obtenir un nouveau vecteur de cette même base.

IV-A-3. Évaluation du polynôme

On souhaite pour terminer évaluer nos polynômes en faisant simplement p(2).

Pour cela, on va donc rendre nos objets callable en ajoutant une méthode __call__() à notre classe :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Polynome_lagrange: 
    ...  
    def __call__(self, X): 
        # permet d'évaluer le polynôme d'interpolation de Lagrange en fonction de X et des valeurs de x et y 
  
        # initialisation de la variable Lx 
        Lx = 0 
  
        # parcours des y 
        for j in range(len(self.y)): 
            lj = 1 
            # parcours des x 
            for i in range(len(self.x)): 
                if i!=j: 
                    lj *= (X - self.x[i])/(self.x[j] - self.x[i]) 
            # ajour de la valeur de lj*y[j] à Lx 
            Lx +=self.y[j]*lj 
  
        # renvoie la valeur de Lx 
        return Lx

Testons maintenant cette méthode :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
# création de l'objet de la classe Polynome_lagrange : 
p = Polynome_lagrange(x=[0, 1, 2],y=[1, 2, 5]) 
  
# valeur de x 
x = 2  
  
# évaluation de p(x) 
print("p({0}) = ".format(x) + str(p(x)))

Le code affiche :

p(2) = 5.0

IV-B. Module complet

On donne pour finir le code complet du module contenant la classe Polynome_lagrange :

Code Python : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import numpy as np 
  
class Polynome_lagrange(): 
  
    def __init__(self, x, y): 
        # méthode constructeur de la classe 
  
        # on définit la liste de valeurs en x permettant d'obtenir la famille de polynômes (l0, l1, ..., ln) représentant une base dans ℝn[X] 
        self.x = x 
  
        # on définit le tableau de valeurs en y représentant les coordonnées du vecteur (tableau numpy) 
        self.y = np.array(y) 
  
  
    def __str__(self): 
        # permet d'afficher le polynôme sous la forme y0*L0(X) + ... + yn*Ln(X) 
  
        Lx = '' 
        # parcours des y 
        for j in range(len(self.y)): 
            Lx +=  str(self.y[j]) + "∙L" + str(j) + "(X)" + " + " 
  
        return Lx[:-3]     
  
    def espace(self): 
        # retourne l'espace vectoriel du polynôme self : R2[X] 
  
        n = len(self.x)-1 
  
        # retourne l'espace vectoriel du polynôme d'interpolation de Lagrange 
        return "ℝ{0}[X]".format(n) 
  
  
    def base(self): 
        # retourne la base de polynômes de self : (L0, L1, L2), x = [0, 1, 2] 
  
        n = len(self.x)-1 
        base = ""  
  
        # parcours des indices des polynômes de lagrange Li 
        for i in range(n+1): 
            base += "L" + str(i) + ", " 
  
        # création de la famille : (L0, L1, L2) 
        base = "(" + base[:-2] + ")" 
  
        # retourne la base du polynôme d'interpolation de Lagrange 
        return "{0}, x = {1}".format(base, self.x) 
  
  
  
    def __add__(self, other): 
        # méthode permettant de redéfinir l'opérateur « + » pour 2 polynômes d'interpolation de Lagrange ou 2 vecteurs 
        # (y0*L0(X) + ... + yn*Ln(X)) + (z0*L0(X) + ... + zn*Ln(X)) = (y0 + z0)*L0(X) + ... + (yn + zn)*Ln(X) 
  
        # si les 2 vecteurs self et other ont la même base 
        if self.x==other.x: 
  
            # addition des 2 vecteurs self.y et other.y (2 tableaux numpy) 
            y = self.y + other.y 
  
            # renvoie le polynômes résultat de l'addition des 2 polynômes self et other 
            return Polynome_lagrange(self.x, y) 
  
        else: # sinon 
  
            print("Les 2 polynômes n'ont pas la même base !") 
  
  
    def __mul__(self, s): 
        # méthode permettant de multiplier le polynôme self par un scalaire 
        # : s*(y0*L0(X) + ... + yn*Ln(X)) = s*y0*L0(X) + ... + s*yn*Ln(X) 
  
        # multiplication du vecteur self.y par le scalaire s 
        y = s*self.y 
  
        # renvoie le polynôme d'interpolation de Lagrange résultat de la multiplication de self par le scalaire s 
        return Polynome_lagrange(self.x, y) 
  
  
    def __eq__(self, other): 
        # méthode permettant de redéfinir l'opérateur « == » pour 2 polynômes d'interpolation de Lagrange 
  
        # renvoie True si les bases et les listes de coordonnées des vecteurs sont identiques 
        return (self.x==other.x) and np.array_equal(self.y,other.y) 
  
  
    def __call__(self, X): 
        # permet d'évaluer le polynôme d'interpolation de Lagrange en fonction de X et des valeurs de x et y 
  
        # initialisation de la variable Lx 
        Lx = 0 
  
        # parcours des y 
        for j in range(len(self.y)): 
            lj = 1 
            # parcours des x 
            for i in range(len(self.x)): 
                if i!=j: 
                    lj *= (X - self.x[i])/(self.x[j] - self.x[i]) 
            # ajour de la valeur de lj*y[j] à Lx 
            Lx +=self.y[j]*lj 
  
        # renvoie la valeur de Lx 
        return Lx 
  
  
# addition de 2 polynômes 
  
print("I-A. Addition de 2 polynômes d'interpolation de Lagrange\n") 
  
# création du 1er objet de la classe Polynome_lagrange 
p1 = Polynome_lagrange(x=[0, 1, 2], y=[0, 1, 4]) 
  
# création du 2e objet de la classe Polynome_lagrange 
p2 = Polynome_lagrange(x=[0, 1, 2], y=[1, 2, 5]) 
  
# affiche l'expression des polynômes p1 et p2 
print("p1 = " + str(p1)) 
print("p2 = " + str(p2)) 
  
print() 
  
# affiche l'appartenance de p1 et p2 à leur espace vectoriel : R2[X], Base = [L0, L1, L2], x = [0, 1, 2] 
print("p1 ∈ " + p1.espace() + ", Base = " + p1.base()) 
print("p2 ∈ " + p1.espace() + ", Base = " + p2.base()) 
  
print() 
  
print("p = p1 + p2") 
  
# addition des 2 polynômes 
p = p1 + p2 
  
print() 
  
# affiche le résultat de l'addition 
print("p = " + str(p)) 
print() 
  
# affiche l'appartenance de p à son espace vectoriel 
print("p ∈ " + p.espace() + ", Base = " + p.base()) 
  
print();print() 
  
# multiplication d'un polynôme par un scalaire 
  
print("I-B. Multiplication d'un polynôme d'interpolation de Lagrange par un scalaire\n") 
  
# création de l'objet de la classe Polynome_lagrange : 
p1 = Polynome_lagrange(x=[0, 1, 2], y=[1, 2, 5]) 
  
# affiche l'expression du polynôme p1 
print("p1 = " + str(p1)) 
  
print() 
  
# affiche l'appartenance de p1 à son espace vectoriel 
print("p1 ∈ " + p1.espace() + ", Base = " + p1.base()) 
  
print() 
  
# définition du scalaire s 
s = 2 
  
print("s = " + str(s)) 
  
print() 
  
print("p = p1*s ") 
  
# multiplication du polynôme p1 par le scalaire s 
p = p1*s 
  
print() 
  
# affiche le résultat de la multiplication de p1 par s 
print("p = " + str(p)) 
print() 
  
# affiche l'appartenance de p à son espace vectoriel 
print("p ∈ " + p.espace() + ", Base = " + p.base()) 
  
print();print() 
  
print("I-C. Évaluation d'un polynôme d'interpolation de Lagrange\n") 
  
# création de l'objet de la classe Polynome_lagrange : 
p = Polynome_lagrange(x=[0, 1, 2],y=[1, 2, 5]) 
  
# affiche l'expression du polynômes p 
print("p = " + str(p)) 
  
print() 
  
# affiche l'appartenance de p à son espace vectoriel 
print("p ∈ " + p.espace() + ", Base = " + p.base()) 
  
# définition de la valeur de x 
x = 2 
  
print() 
  
# évaluation de p(x) 
print("p({0}) = ".format(x) + str(p(x)))

Note : la librairie scipy propose également une classe lagrange permettant de définir ce type de polynôme.

V. Conclusion

Comme on a pu le montrer, l'ensemble des polynômes construits sur la base des polynômes de Lagrange (l0, l1, …, ln) constitue donc un espace vectoriel muni de lois de composition interne et externe, à savoir l'addition et la multiplication par un scalaire.

Les éléments de cet espace peuvent facilement être représentés en Python afin de pouvoir ensuite réaliser des opérations entre ces objets mathématiques comme on le ferait sur des vecteurs.

On peut bien sûr imaginer de construire l'ensemble n[X] des polynômes sur la base usuelle des monômes Xn.

Sources :

https://fr.wikipedia.org/wiki/Espace_vectoriel
https://fr.wikipedia.org/wiki/Corps_commutatif
https://fr.wikipedia.org/wiki/Loi_de_composition
https://fr.wikipedia.org/wiki/Base_(...lin%C3%A9aire)
https://fr.wikipedia.org/wiki/Combinaison_lin%C3%A9aire
https://fr.wikipedia.org/wiki/Interp...n_lagrangienne
https://pyspc.readthedocs.io/fr/late...aux_numpy.html

Une erreur dans cette actualité ? Signalez-nous-la !