[Actualité] Calcul formel en Python : étendre les opérations sur les nombres entiers à d'autres objets mathématiques
par
, 04/03/2024 à 09h11 (3886 Affichages)
I. Introduction
On souhaite étendre les opérations d'addition et de multiplication effectuées sur les nombres entiers à d'autres objets mathématiques représentant les éléments d'un anneau.
D'après Wikipedia, en algèbre, un anneau est un ensemble muni de deux lois de composition interne appelées addition et multiplication, qui vérifient des propriétés analogues à celles de ces opérations sur les entiers relatifs.
Une loi de composition interne est 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.
On va d'abord montrer brièvement dans ce billet que l'ensemble des nombres complexes et celui des polynômes sont des anneaux.
Dans un second temps, on va représenter les éléments de ces ensembles à l'aide de classes en Python, puis définir les opérations d'addition et de multiplication entre ces objets mathématiques en utilisant la surcharge d'opérateur.
Enfin, on va tester le code Python en effectuant différentes opérations sur ces nouveaux objets un peu comme on le ferait sur des nombres entiers.
II. Exemples d'anneaux
De façon plus détaillée, un anneau est un ensemble E dans lequel sont données deux lois de composition interne, notées + et ×, vérifiant les propriétés suivantes :
- La loi + est associative : pour tous a, b, c ∈ E, a + (b + c) = (a + b) + c ;
- La loi + est commutative : pour tous a, b ∈ E, a + b = b + a ;
- La loi + possède un élément neutre ;
- La loi × est associative : pour tous a, b, c ∈ E, a × (b × c) = (a × b) × c ;
- La loi × est distributive par rapport à la loi + : pour tout a, b, c ∈ E, on a a × (b + c) = a × b + a × c et (b + c) × a = b × a + c × a ;
- La loi × possède un élément neutre ;
- Tout élément a appartenant à l'ensemble E possède un opposé, noté –a.
Note : si on veut être précis, on devrait plutôt parler d'anneau unitaire.
Nous allons donc le vérifier maintenant sur deux exemples.
II-A. Ensemble ℂ des nombres complexes
En mathématiques, l'ensemble des nombres complexes, noté ℂ, est créé comme extension de l'ensemble des nombres réels, contenant en particulier un nombre imaginaire noté i, tel que i2 = −1. Le carré de (−i) est aussi égal à −1 : (−i)2 = −1.
Tout nombre complexe peut s'écrire sous la forme a + ib où a et b sont des nombres réels.
II-A-1. Addition de nombres complexes
L'addition de 2 nombres complexes z1 = a + ib et z2 = c + id écrits sous forme algébrique, est définie de la manière suivante :
(a + ib) + (c + id) = (a+b) + i(b+d)
Le résultat donne également un nombre complexe et cette opération est donc bien une loi de composition interne dans ℂ.
Soient maintenant les trois nombres complexes z1, z2 et z3
1) Associativité
On vérifie facilement en utilisant l'égalité précédente la propriété d'associativité de l'addition de nombres complexes :
z1 + (z2 + z3) = (z1 + z2) + z3
2) et 3) On peut montrer également que l'addition est commutative et que le complexe nul est l'élément neutre pour l'addition dans ℂ.
II-A-2. Multiplication de nombres complexes
La multiplication de 2 nombres complexes z1 = a + ib et z2 = c + id, est définie par :
(a + ib) × (c + id) = (ac - bd) + i(ad + bc)
Le résultat de la multiplication de deux nombres complexes donne aussi un nombre complexe et cette opération est donc bien une loi de composition interne dans ℂ.
Soient maintenant les nombres complexes z1, z2 et z3
4) Associativité
On vérifie facilement en utilisant l'égalité précédente la propriété d'associativité de la multiplication :
z1 × (z2 × z3) = (z1 × z2) × z3
5) Distributivité par rapport à l'addition
De même, on vérifie aisément la propriété de distributivité de la multiplication par rapport à l'addition :
z1 × (z2 + z3) = z1 × z2 + z1 × z3
(z2 + z3) × z1 = z2 × z1 + z3 × z1
6) et 7) On peut montrer enfin que le nombre 1 est l'élément neutre pour la multiplication dans ℂ et que tout élément de cet ensemble possède un opposé.
En conclusion, les opérations d'addition et de multiplication sont des lois de composition interne dans l'ensemble ℂ qui vérifient des propriétés analogues à celles de ces opérations sur les entiers relatifs.
Par conséquent l'ensemble ℂ constitue un anneau.
II-B. Ensemble ℝ[X] des polynômes
En mathématiques, un polynôme de la variable X peut s'écrire sous la forme :
P(X) = a0 + a1X + ... + an-1Xn-1 + anXn
Où X est une variable appelée indéterminée (dans notre cas un réel), les constantes a0, a1, ..., an sont les coefficients réels du polynôme et n est un entier naturel.
II-B-1. Addition de polynômes
Soient 2 polynômes de la forme :
P1(X) = a0 + a1X + ... + an-1Xn-1 + anXn
P2(X) = b0 + b1X + ... + bm-1Xm-1 + bnXm
L'addition de ces 2 polynômes P1(X) et P2(X) donne pour n=m :
P1(X) + P2(X) = (a0 + b0) + (a1 + b1)X + ... + (an-1 + bn-1)Xn-1 + (an + bn)Xn
Et pour n>m :
P1(X) + P2(X) = (a0 + b0) + (a1 + b1)X + ... + (am-1 + bm-1)Xm-1 + (am + bm)Xm + ... + anXn
On additionne donc simplement les coefficients de même degré et on obtient donc un troisième polynôme.
Par conséquent, cette opération est bien une loi de composition interne dans ℝ[X].
Soient maintenant les trois polynômes P1, P2 et P3
1) Associativité
On vérifie facilement en utilisant le résultat précédent la propriété d'associativité de l'addition de polynômes :
P1 + (P2 + P3) = (P1 + P2) + P3
2) et 3) On peut montrer également que l'addition est commutative et que le polynôme nul est l'élément neutre pour l'addition dans ℝ[X].
II-B-2. Multiplication de polynômes
Soient 2 polynômes de degré 1 :
P1(X) = a0 + a1X
P2(X) = b0 + b1X
La multiplication étant distributive par rapport à l'addition, le produit de ces 2 polynômes P1(X) et P2(X) nous donne :
P1(X) X P2(X) = (a0 + a1X)(b0 + b1X)
P1(X) X P2(X) = a0b0 + a0b1X + a1b0X + a1b1X2
On obtient donc à nouveau un troisième polynôme, et on peut ainsi généraliser facilement ce résultat à des polynômes de degrés quelconques.
Par conséquent, cette opération est bien une loi de composition interne dans ℝ[X].
Soient maintenant les polynômes P1, P2 et P3
4) Associativité
On vérifie facilement en utilisant le résultat précédent la propriété d'associativité de la multiplication :
P1 × (P2 × P3) = (P1 × P2) × P3
5) Distributivité par rapport à l'addition
De même, on vérifie aisément la propriété de distributivité de la multiplication de polynômes par rapport à l'addition :
P1 × (P2 + P3) = P1 × P2 + P1 × P3
(P2 + P3) × P1 = P2 × P1 + P3 × P1
6) et 7) On peut montrer enfin que le polynôme constant 1 est l'élément neutre pour la multiplication dans ℝ[X] et que tout élément de cet ensemble possède un opposé.
En conclusion, les opérations d'addition et de multiplication sont des lois de composition interne dans l'ensemble ℝ[X] qui vérifient des propriétés analogues à celles de ces opérations sur les entiers relatifs.
Par conséquent l'ensemble ℝ[X] constitue un anneau.
III. Implémentation en Python
Les opérations d'addition et de multiplication sur ces objets mathématiques ont donc des propriétés communes avec celles sur les nombres entiers, toutefois elles ont aussi leurs particularités et ne sont pas définies de la même manière (on parle dans ce cas de polymorphisme).
On va maintenant représenter les nombres complexes et les polynômes à l'aide de classes en Python, puis définir les opérations d'addition et de multiplication entre ces objets mathématiques en utilisant la surcharge d'opérateur.
III-A. Création de la classe Complexe
Pour définir ces nombres complexes en Python et pouvoir réaliser des opérations entre eux, il nous faut créer une classe Complexe :
Notre classe comportera en plus une méthode particulière __init__() dont le code est exécuté quand la classe est instanciée.
Elle va nous permettre de définir les parties réelle et imaginaire du nombre complexe au moment de créer l'objet :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 class Complexe: def __init__(self, part_reel=0, part_imag=0): # méthode constructeur de la classe # on définit la partie réelle du nombre complexe self.reel = part_reel # on définit la partie imaginaire du nombre complexe self.imag = part_imag def __str__(self): # permet d'afficher le nombre complexe sous la forme algébrique a + bi return "{0} + {1}i".format(self.reel, self.imag) if self.imag>=0 else "{0} - {1}i".format(self.reel, abs(self.imag))
La méthode __str__ permet d'afficher un nombre complexe sous la forme a + bi.
Pour tester ces méthodes, nous ajoutons simplement deux lignes au module :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 z = Complexe(1, 2) # création de l'objet Complexe : 1 + 2i print(z) # affiche le nombre complexe
Le code affiche :
1 + 2i
III-A-1. Surcharge de l'opérateur d'addition
Pour surcharger l'opérateur « + » et pouvoir ainsi réaliser l'addition de 2 nombres complexes, nous devons ajouter une méthode __add __ () à la classe :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 class Complexe: .... def __add__(self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 nombres complexes : z1 + z2 = (a + bi) + (c + di) = (a+c) + (b+d)i # on évalue la partie réelle du nombre complexe résultat de l'addition part_reel = self.reel + other.reel # on évalue la partie imaginaire du nombre complexe résultat de l'addition part_imag = self.imag + other.imag # renvoie le nombre complexe résultat de l'addition return Complexe(part_reel, part_imag)
Cette méthode permet donc de redéfinir l'opération « + » pour les nombres complexes en utilisant l'égalité :
(a + bi) + (c + di) = (a+c) + (b+d)i
Pour tester l'opérateur d'addition portant sur 2 objets de la classe Complexe, nous ajoutons ces lignes de code :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # création du 1er objet de la classe Complexe : 1 + 2i z1 = Complexe(1, 2) # création de 2e objet Complexe : 2 + 3i z2 = Complexe(2, 3) # affiche l'appartenance de z1 et z2 à l'ensemble ℂ print(str(z1) + " ∈ " + anneau(z1)) print(str(z2) + " ∈ " + anneau(z2)) print() # addition des 2 nombres complexes z = z1+z2 # affiche le résultat de l'addition print("(" + str(z1) + ")" + " + " + "(" + str(z2) + ")" + " = " + str(z)) print() # affiche l'appartenance de z à l'ensemble ℂ print(str(z) + " ∈ " + anneau(z))
Le code affiche :
1 + 2i ∈ ℂ
2 + 3i ∈ ℂ
(1 + 2i) + (2 + 3i) = 3 + 5i
3 + 5i ∈ ℂ
La fonction anneau(element) renvoie l'ensemble (ℂ, ℝ[X], etc.) auquel appartient l'élément, elle est présente dans le module donné à la fin du billet.
On peut également vérifier la propriété d'associativité de l'addition :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 ... # création de 3e objet Complexe : 2 + 2i z3 = Complexe(2, 2) # affiche les nombres complexes z1, z2 et z2 print("z1 = " + str(z1)) print("z2 = " + str(z2)) print("z3 = " + str(z3)) # vérification de la propriété d'associativité de l'addition dans ℂ r1 = z1 + (z2 + z3) r2 = (z1 + z2) + z3 print() if r1==r2: # si r1=r2 print("z1 + (z2 + z3) = (z1 + z2) + z3") else: print("z1 + (z2 + z3) ≠ (z1 + z2) + z3")
Le code affiche :
z1 = 1 + 2i
z2 = 2 + 3i
z3 = 2 + 2i
z1 + (z2 + z3) = (z1 + z2) + z3
III-A-2. Surcharge de l'opérateur de multiplication
Pour surcharger l'opérateur « * » et l'appliquer à 2 nombres complexes, nous devons également ajouter une méthode __mul __ () à la classe :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 class Complexe: ... def __mul__(self, other): # méthode permettant de redéfinir l'opérateur « * » pour 2 nombres complexes : z1 * z2 = (ac - bd) + (ad + bc)*i # part_reel = (ac - bd) part_reel = self.reel * other.reel - self.imag * other.imag # part_imag = (ad + bc) part_imag = self.reel * other.imag + self.imag * other.reel # renvoie le nombre complexe résultat de la multiplication return Complexe(part_reel, part_imag)
Cette méthode offre donc la possibilité de redéfinir l'opération de multiplication pour 2 nombres complexes en utilisant l'égalité :
(a + bi) x (c + di) = (ac - bd) + (ad + bc)i
Pour tester l'opérateur de multiplication portant sur 2 objets de la classe Complexe, nous ajoutons ces lignes :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # création du 1er objet de la classe Complexe : 1 + 2i z1 = Complexe(1, 2) # création du 2e objet de la classe Complexe : 2 + 3i z2 = Complexe(2, 3) # affiche l'appartenance de z1 et z2 à l'ensemble ℂ print(str(z1) + " ∈ " + anneau(z1)) print(str(z2) + " ∈ " + anneau(z2)) print() # produit des 2 nombres complexes z = z1*z2 # affiche le résultat du produit print("(" + str(z1) + ")" + "(" + str(z2) + ")" + " = " + str(z)) print() # affiche l'appartenance de z à l'ensemble ℂ print(str(z) + " ∈ " + anneau(z))
Le code affiche :
1 + 2i ∈ ℂ
2 + 3i ∈ ℂ
(1 + 2i)(2 + 3i) = -4 + 7i
-4 + 7i ∈ ℂ
On peut également vérifier la propriété d'associativité de la multiplication :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 ... # création de 3e objet Complexe : 2 + 2i z3 = Complexe(2, 2) # affiche les nombres complexes z1, z2 et z2 print("z1 = " + str(z1)) print("z2 = " + str(z2)) print("z3 = " + str(z3)) # vérification de la propriété d'associativité de la multiplication dans ℂ r1 = z1 * (z2 * z3) r2 = (z1 * z2) * z3 print() if r1==r2: # si r1=r2 print("z1 * (z2 * z3) = (z1 * z2) * z3") else: print("z1 * (z2 * z3) ≠ (z1 * z2) * z3")
Le code affiche :
z1 = 1 + 2i
z2 = 2 + 3i
z3 = 2 + 2i
z1 * (z2 * z3) = (z1 * z2) * z3
III-B. Création de la classe Polynome
Pour définir ces polynômes en Python et pouvoir réaliser des opérations entre eux, il nous faut créer une classe Polynome :
Sa méthode constructeur __init__() va nous permettre de définir la liste des coefficients du polynôme au moment de créer l'objet :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 class Polynome: def __init__(self, liste_coefs=[0]): # méthode constructeur de la classe # on définit la liste des coefficients du polynôme [a0, a1, ..., an] self.coefs = liste_coefs # suppression si nécessaire des zéros en queue de liste de coefficients. Exemple : [2, 3, 1, 0, 0] -> [2, 3, 1] self.reduire() def __str__(self): ...
La méthode __str__ permet d'afficher un polynôme sous la forme 1 + 2.x + x^2.
Pour tester ces méthodes, nous ajoutons deux lignes au module :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 p = Polynome([1, 2, 1]) # création de l'objet Polynome : 1 + 2x + x^2 print(p) # affiche l'expression du polynôme
Le code affiche :
1 + 2⋅X + X^2
Note importante : la liste de coefficients permettant de créer l'objet Polynome contient également les coefficients nuls.
Par exemple, le polynôme P(x) = x^2 + 2⋅X^4 sera représenté par la liste [0, 0, 1, 0, 2] .
III-B-1. Surcharge de l'opérateur d'addition
Pour surcharger l'opérateur « + » et pouvoir ainsi réaliser l'addition de 2 polynômes, nous devons ajouter une méthode __add __ () à la classe :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 class Polynome: ... def __add__(self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 polynômes : (1 + 2x + x^2) + (1 + x) = 2 + 3x + x^2 # p1 = self, p2 = other if len(other.coefs) >len(self.coefs): # si degré de p2 > degré de p1 # on copie les coefs du polynôme de degré le plus élevé et la longueur de la liste de coefs la plus petite. liste_coefs = other.coefs[:]; n = len(self.coefs) else: liste_coefs = self.coefs[:]; n = len(other.coefs) # sinon, ... for i in range(n): # parcours des indices de liste_coefs liste_coefs[i] = self.coefs[i] + other.coefs[i] # addition des coefficients de degré i # renvoie le polynôme résultat de l'addition return Polynome(liste_coefs)
Cette méthode permet donc de redéfinir l'opération « + » pour les polynômes en additionnant les coefficients de même degré.
Pour tester l'opérateur d'addition portant sur 2 objets de la classe Polynome, nous ajoutons ces lignes de code :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # création du 1er objet de la classe Polynome : 1 + 2x + x^2 p1 = Polynome([1, 2, 1]) # création du 2e objet Polynome : 1 + x p2 = Polynome([1, 1]) # affiche l'appartenance de p1 et p2 à l'ensemble ℝ[X] print(str(p1) + " ∈ " + anneau(p1)) print(str(p2) + " ∈ " + anneau(p2)) print() # addition des 2 polynômes p = p1+p2 # affiche le résultat de l'addition print("(" + str(p1) + ")" + " + " + "(" + str(p2) + ")" + " = " + str(p)) print() # affiche l'appartenance de p à l'ensemble ℝ[X] print(str(p) + " ∈ " + anneau(p))
Le code affiche :
1 + 2⋅X + X^2 ∈ ℝ[X]
1 + X ∈ ℝ[X]
(1 + 2⋅X + X^2) + (1 + X) = 2 + 3⋅X + X^2
2 + 3⋅X + X^2 ∈ ℝ[X]
III-B-2. Surcharge de l'opérateur de multiplication
Pour surcharger l'opérateur « * » et l'appliquer à 2 polynômes, nous devons également ajouter une méthode __mul __ () à la classe :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 class Polynome: ... def __mul__(self, other): # méthode permettant de redéfinir l'opérateur « * » pour 2 polynômes : (1 + x) * (1 + 2x) = 1 + 3x + 2x^2 # initialisation de la liste des coefficients qu'avec des zéros liste_coefs=[0]*(len(self.coefs)+len(other.coefs)-1) # exemple : [0, 0, 0] for i1 in range(len(self.coefs)): # parcours des indices des coefs du polynôme n°1 for i2 in range(len(other.coefs)): # parcours des indices des coefs du polynôme n°2 # multiplication des coefficients d'indices i1 et i2 liste_coefs[i1+i2] = liste_coefs[i1+i2] + self.coefs[i1]*other.coefs[i2] # création de l'objet Polynome basé sur la liste poly=Polynome(liste_coefs) return poly # renvoie le polynôme résultat de la multiplication
Cette méthode permet donc de redéfinir l'opération de multiplication pour 2 polynômes en utilisant la propriété de distributivité de la multiplication par rapport à l'addition.
Pour tester l'opérateur de multiplication portant sur 2 objets de la classe Polynome, nous ajoutons simplement ces lignes :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # création du 1er objet de la classe Polynome : 1 + x p1 = Polynome([1, 1]) # création du 2e objet de la classe Polynome : 1 + 2x p2 = Polynome([1, 2]) # affiche l'appartenance de p1 et p2 à l'ensemble ℝ[X] print(str(p1) + " ∈ " + anneau(p1)) print(str(p2) + " ∈ " + anneau(p2)) print() # produit des 2 polynômes p = p1*p2 # affiche le résultat de la multiplication de p1 par p2 print("(" + str(p1) + ")" + "(" + str(p2) + ")" + " = " + str(p)) print() # affiche l'appartenance de p à l'ensemble ℝ[X] print(str(p) + " ∈ " + anneau(p))
Le code affiche :
1 + X ∈ ℝ[X]
1 + 2⋅X ∈ ℝ[X]
(1 + X)(1 + 2⋅X) = 1 + 3⋅X + 2⋅X^2
1 + 3⋅X + 2⋅X^2 ∈ ℝ[X]
On peut bien sûr imaginer d'étendre à ces objets mathématiques d'autres opérations effectuées sur les nombres entiers (soustraction, puissance, etc.).
IV. Module complet
On donne pour finir le code complet du module contenant les deux classes :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334 class Complexe: def __init__(self, part_reel=0, part_imag=0): # méthode constructeur de la classe # on définit la partie réelle du nombre complexe self.reel = part_reel # on définit la partie imaginaire du nombre complexe self.imag = part_imag def __str__(self): # permet d'afficher le nombre complexe sous la forme algébrique a + bi return "{0} + {1}i".format(self.reel, self.imag) if self.imag>=0 else "{0} - {1}i".format(self.reel, abs(self.imag)) def __add__(self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 nombres complexes : z1 + z2 = (a + bi) + (c + di) = (a+c) + (b+d)i # on évalue la partie réelle du nombre complexe résultat de l'addition part_reel = self.reel + other.reel # on évalue la partie imaginaire du nombre complexe résultat de l'addition part_imag = self.imag + other.imag # renvoie le nombre complexe résultat de l'addition return Complexe(part_reel, part_imag) def __mul__(self, other): # méthode permettant de redéfinir l'opérateur « * » pour 2 nombres complexes : z1 * z2 = (ac - bd) + (ad + bc)*i # part_reel = (ac - bd) part_reel = self.reel * other.reel - self.imag * other.imag # part_imag = (ad + bc) part_imag = self.reel * other.imag + self.imag * other.reel # renvoie le nombre complexe résultat de la multiplication return Complexe(part_reel, part_imag) def __pow__(self, n): # méthode permettant de redéfinir l'opérateur de puissance : self ** n # on initialise la variable objet z avec la valeur 1 élément neutre pour la multiplication de nombres complexes z = Complexe(1,0) # nous multiplions n fois z par self à l'aide de l'opérateur * for i in range(n): z = z*self # équivalent à : z = z.__mul__(self) # renvoie le nombre complexe résultat de l'opération (self ** n) return z def __eq__(self, other): # méthode permettant de redéfinir l'opérateur « == » pour 2 nombres complexes # renvoie True si les parties réelles et imaginaires des 2 nombres complexes sont égales return (self.reel==other.reel) and (self.imag==other.imag) class Polynome: def __init__(self, liste_coefs=[0]): # méthode constructeur de la classe # on définit la liste des coefficients du polynôme [a0, a1, ..., an] self.coefs = liste_coefs # suppression si nécessaire des zéros en queue de liste de coefficients. Exemple : [2, 3, 1, 0, 0] -> [2, 3, 1] self.reduire() def __str__(self): # permet d'afficher le polynôme sous la forme 1 + 2x + 3x^2 s="" # initialisation de la chaîne de caractères # on vérifie dabord si le degré du polynôme est nul if (len(self.coefs)-1==0): return str(self.coefs[0]) else: # sinon if self.coefs[0]!=0: s=str(self.coefs[0]) + " + " for i in range(1, len(self.coefs)): # parcours des indices des coefficients du polynôme : [a1, a2, ..., an] if self.coefs[i]!=0: # si le coefficient de degré i n'est pas nul if self.coefs[i]!=1: # si le coefficient de degré i est différent de 1 s+="{}⋅X^{} + ".format(self.coefs[i],i) else: s+="X^{} + ".format(i) # élimination des caractères en trop s = s[:-3].replace("+ -", "- ").replace("X^1 ","X ").replace(" 1⋅X"," X") if s[-2:]=="^1": s = s[:-2] if s[:3]=="1⋅X": s = s[3:] return s # on retourne l'expression du polynôme def eval_degre(): # retourne le degré du polynôme return (len(self.coefs)-1) def __add__(self, other): # méthode permettant de redéfinir l'opérateur « + » pour 2 polynômes : (1 + 2x + x^2) + (1 + x) = 2 + 3x + x^2 # p1 = self, p2 = other if len(other.coefs) >len(self.coefs): # si degré de p2 > degré de p1 # on copie les coefs du polynôme de degré le plus élevé et la longueur de la liste de coefs la plus petite. liste_coefs = other.coefs[:]; n = len(self.coefs) else: liste_coefs = self.coefs[:]; n = len(other.coefs) # sinon, ... for i in range(n): # parcours des indices de liste_coefs liste_coefs[i] = self.coefs[i] + other.coefs[i] # addition des coefficients de degré i # renvoie le polynôme résultat de l'addition return Polynome(liste_coefs) def reduire(self): # tant que le dernier élément de la liste est nul while self.coefs[-1] == 0 and len(self.coefs)>1: self.coefs.pop() # supprimer le dernier élément def __mul__(self, other): # méthode permettant de redéfinir l'opérateur « * » pour 2 polynômes : (1 + x) * (1 + 2x) = 1 + 3x + 2x^2 # initialisation de la liste des coefficients qu'avec des zéros liste_coefs=[0]*(len(self.coefs)+len(other.coefs)-1) # exemple : [0, 0, 0] for i1 in range(len(self.coefs)): # parcours des indices des coefs du polynôme n°1 for i2 in range(len(other.coefs)): # parcours des indices des coefs du polynôme n°2 # multiplication des coefficients d'indices i1 et i2 liste_coefs[i1+i2] = liste_coefs[i1+i2] + self.coefs[i1]*other.coefs[i2] # création de l'objet Polynome basé sur la liste poly=Polynome(liste_coefs) return poly # renvoie le polynôme résultat de la multiplication def __pow__(self, n): # méthode permettant de redéfinir l'opérateur de puissance : self ** n # on crée l'objet poly à partir d'une liste contenant un seul élément 1, élément neutre pour la multiplication des polynômes poly = Polynome([1]) for i in range(n): # on multiplie n fois poly par self à l'aide de l'opérateur * poly = poly*self # équivalent à : poly = poly.__mul__(self) return poly # renvoie le polynôme résultat de l'opération (self ** n) def __eq__(poly1, other): # méthode permettant de redéfinir l'opérateur « == » pour 2 polynômes return (poly1.coefs==other.coefs) # renvoie True si les 2 liste de coefficients sont égales def eval(self,x): # méthode permettant d'évaluer le polynôme en fonction de x # intialisation des variables valeur_polynome = self.coefs[0] # valeur_polynome = a0 power=1 for coef in self.coefs[1:]: # parcours des coefficients du polynôme à partir de a1 : a1, a2, ..., an power = power*x # calcul de la puissance de x pour ai : power = x^i valeur_polynome += coef*power # valeur_polynome = valeur_polynome + ai*x^i return valeur_polynome # renvoie la valeur du polynôme def eval_horner(self,x): # méthode permettant d'évaluer le polynôme en fonction de x # intialisation de la variable valeur_polynome = self.coefs[-1] # valeur_polynome = an for coef in reversed(self.coefs[:-1]): # parcours des coefficients du polynôme à partir de an-1 : an-1, ..., a1, a0 valeur_polynome = valeur_polynome*x + coef # valeur_polynome = valeur_polynome*x + ai return valeur_polynome # renvoie la valeur du polynôme def anneau(element): # retourne l'ensemble ou l'anneau auquel appartient l'élément passé en argument # si c'est un objet Complexe if isinstance(element, Complexe): return "ℂ" # si c'est un objet Polynome elif isinstance(element, Polynome): return "ℝ[X]" # si c'est un entier elif isinstance(element, int): return "Z" else: # sinon return "" # addition de 2 nombres complexes print("I-A. Addition de 2 nombres complexes\n") # création du 1er objet de la classe Complexe : 1 + 2i z1 = Complexe(1, 2) # création de 2e objet Complexe : 2 + 3i z2 = Complexe(2, 3) # affiche l'appartenance de z1 et z2 à l'ensemble ℂ print(str(z1) + " ∈ " + anneau(z1)) print(str(z2) + " ∈ " + anneau(z2)) print() # addition des 2 nombres complexes z = z1+z2 # affiche le résultat de l'addition print("(" + str(z1) + ")" + " + " + "(" + str(z2) + ")" + " = " + str(z)) print() # affiche l'appartenance de z à l'ensemble ℂ print(str(z) + " ∈ " + anneau(z)) print() print("Vérification de l'associativité de l'addition dans ℂ\n") # création de 3e objet Complexe : 2 + 2i z3 = Complexe(2, 2) # affiche les nombres complexes z1, z2 et z2 print("z1 = " + str(z1)) print("z2 = " + str(z2)) print("z3 = " + str(z3)) # vérification de la propriété d'associativité de l'addition dans ℂ r1 = z1 + (z2 + z3) r2 = (z1 + z2) + z3 print() if r1==r2: # si r1=r2 print("z1 + (z2 + z3) = (z1 + z2) + z3") else: print("z1 + (z2 + z3) ≠ (z1 + z2) + z3") print();print() # multiplication de 2 nombres complexes print("I-B. Multiplication de 2 nombres complexes\n") # création du 1er objet de la classe Complexe : 1 + 2i z1 = Complexe(1, 2) # création du 2e objet de la classe Complexe : 2 + 3i z2 = Complexe(2, 3) # affiche l'appartenance de z1 et z2 à l'ensemble ℂ print(str(z1) + " ∈ " + anneau(z1)) print(str(z2) + " ∈ " + anneau(z2)) print() # produit des 2 nombres complexes z = z1*z2 # affiche le résultat du produit print("(" + str(z1) + ")" + "(" + str(z2) + ")" + " = " + str(z)) print() # affiche l'appartenance de z à l'ensemble ℂ print(str(z) + " ∈ " + anneau(z)) print() print("Vérification de l'associativité de la multiplication dans ℂ\n") # affiche les nombres complexes z1, z2 et z2 print("z1 = " + str(z1)) print("z2 = " + str(z2)) print("z3 = " + str(z3)) # vérification de la propriété d'associativité de la multiplication dans ℂ r1 = z1 * (z2 * z3) r2 = (z1 * z2) * z3 print() if r1==r2: # si r1=r2 print("z1 * (z2 * z3) = (z1 * z2) * z3") else: print("z1 * (z2 * z3) ≠ (z1 * z2) * z3") print();print() # addition de 2 polynômes print("II-A. Addition de 2 polynômes\n") # création du 1er objet de la classe Polynome : 1 + 2x + x^2 p1 = Polynome([1, 2, 1]) # création du 2e objet Polynome : 1 + x p2 = Polynome([1, 1]) # affiche l'appartenance de p1 et p2 à l'ensemble ℝ[X] print(str(p1) + " ∈ " + anneau(p1)) print(str(p2) + " ∈ " + anneau(p2)) print() # addition des 2 polynômes p = p1+p2 # affiche le résultat de l'addition print("(" + str(p1) + ")" + " + " + "(" + str(p2) + ")" + " = " + str(p)) print() # affiche l'appartenance de p à l'ensemble ℝ[X] print(str(p) + " ∈ " + anneau(p)) print();print() # multiplication de 2 polynômes print("II-B. Multiplication de 2 polynômes\n") # création du 1er objet de la classe Polynome : 1 + x p1 = Polynome([1, 1]) # création du 2e objet de la classe Polynome : 1 + 2x p2 = Polynome([1, 2]) # affiche l'appartenance de p1 et p2 à l'ensemble ℝ[X] print(str(p1) + " ∈ " + anneau(p1)) print(str(p2) + " ∈ " + anneau(p2)) print() # produit des 2 polynômes p = p1*p2 # affiche le résultat de la multiplication de p1 par p2 print("(" + str(p1) + ")" + "(" + str(p2) + ")" + " = " + str(p)) print() # affiche l'appartenance de p à l'ensemble ℝ[X] print(str(p) + " ∈ " + anneau(p))
V. Conclusion
Comme on a pu le montrer, l'ensemble des nombres complexes et celui des polynômes constituent donc des anneaux munis de lois de composition interne, à savoir l'addition et la multiplication.
Les éléments de ces anneaux peuvent facilement être représentés en Python afin de pouvoir ensuite réaliser des opérations entre ces objets mathématiques, un peu comme on le ferait sur des nombres entiers.
Ces opérations peuvent bien sûr être étendues à d'autres objets mathématiques, comme par exemple les fonctions continues ou les séries formelles.
Sources :
https://fr.wikipedia.org/wiki/Anneau...C3%A9matiques)
https://fr.wikipedia.org/wiki/Loi_de...sition_interne
https://fr.wikipedia.org/wiki/Nombre_complexe
https://fr.wikipedia.org/wiki/Polyn%C3%B4me
https://fr.wikipedia.org/wiki/Calcul_formel
https://docs.python.org/fr/3/tutorial/classes.html
https://docs.python.org/fr/3/referen...-numeric-types