Lyc´ee Thiers - MPSI-3

publicité
Lycée Thiers
TP PYTHON - 05
Prise de contact avec un logiciel de calcul formel
sympy est un module permettant d’effectuer du calcul symbolique. C’est un exemple de “CAS”,
acronyme pour Computer Algebra System.
sympy est entièrement écrit en Python et ne requiert aucun logicien additionnel pour fonctionner.
Aucune procédure d’installation n’est nécessaire car sympy fait partie de la distribution de Pyzo.
Toutes les commandes qui suivent doivent être saisies. Il est suggéré d’essayer aussi quelques variantes et d’observer les réponses du système, ce qui permettra d’en apprendre davantage.
Pour commencer, on charge le module, comme on l’a déjà fait dans d’autres circonstances (pour le
module math, par exemple) :
>>> from sympy import *
On peut jeter un coup d’oeil à la liste (imposante) de fonctionnalités mises à notre disposition :
>>> dir()
Ce qui suit n’est qu’une introduction sommaire. Pour en savoir plus, on peut consulter la documentation en ligne :
http://docs.sympy.org/latest/index.html
premières manipulations
Afin de commencer à tester quelques unes de ces fonctionnalités, il faut créer des symboles (généralement, on les nomme avec des lettres minuscules, mais ce n’est pas une obligation). La fonction var
accepte une chaîne de caractères et crée un ou plusieurs symboles :
>>>
>>>
>>>
>>>
var(’x’)
var(’y,z’)
var(’a b’)
var(’r:3’)
# noter la virgule
# noter le caractère ’espace’
# ceci crée des symboles numérotés
Observer que x est une instance d’une classe particulière (et, bien sûr, même chose pour les autres
symboles nouvellement créés) :
>>> type(x)
On peut maintenant former des expressions :
>>> x + 1
>>> x + y + 2 - 2*(y-1) - 3 + y
# à reproduire fidèlement !
Comme toujours, les espaces sont ignorés (on peut en insérer, afin d’augmenter la lisibilité). Par
ailleurs, l’exemple ci-dessus montre que sympy tente, dans la mesure du possible, de réduire l’expression saisie par l’utilisateur à une forme standard, en utilisant des règles de simplification. Mais
certaines transformations ne sont pas effectuées de manière automatique :
TP PYTHON - 05
2
>>> (x+1)**3
On peut alors décider d’orienter le calcul dans telle ou telle direction, selon ce qu’on cherche à faire.
Par exemple :
>>> expand((x+1)**3)
>>> ((x+1)**3).expand()
# version fonction
# version méthode
On aurait pu écrire, de façon équivalente : expand(_) car le symbole _ fait référence au résultat de
l’évaluation précédente. Autre exemple :
>>> expand((x+y+z)**3 * (x-y+1)**2 * (x+y+1) * (y+2*z))
>>> factor(_)
Impressionant, non ?
Au cas où vous en douteriez encore, expand et factor permettent respectivement de développer et
de factoriser une expression algébrique (comportant une ou plusieurs variables).
L’affichage du résultat peut être rendu plus “joli”, mais cela n’a rien d’essentiel :
>>> init_printing(pretty_print = True)
>>> expand((x+y)**4)
Voici deux autres exemples montrant que certaines simplifications ne se font pas automatiquement :
>>> (x**3 - y**3) / (x - y)
>>> cancel(_)
>>> log(x*y)
Dans ce dernier exemple, il faut préciser que la fonction log est celle prédéfinie par le module sympy
(elle s’applique à des expressions comportant des symboles, et pas seulement à des expressions numériques, comme c’est le cas de la fonction log du module math). Si le module math avait été chargé avant
le module sympy, la définition de log par math aurait été écrasée (ainsi que les définitions de quelques
autres fonctions, pour lesquelles une fonction portant le même nom existe dans sympy. Ce comportement n’est pas génant ici, mais pourrait l’être dans d’autres circonstances : la solution consiste à
charger un module via la commande import nomDuModule au lieu de from nomDuModule import * ; on
doit allors accéder aux fonctions par leur nom complet, c’est-à-dire nomDuModule.nomDeLaFonction).
Il est normal qu’aucune simplification de l’expression log(x*y) n’ait eu lieu ! En revanche, si l’on
sait que les symboles x et y représentent des nombres réels strictement positifs, alors on est en droit
d’attendre autre chose :
>>> var(’x,y’, positive = True)
>>> expand(log(x*y))
Concernant les fractions, les deux transformations de base sont, d’une part, la réduction au même
dénominateur :
>>> var(’r:3’)
>>> 1/r0 + 1/r1 + 1/r2
>>> together(_)
et, d’autre part, la décomposition en éléments simples (mais seulement pour des fractions en une
seule variable) :
>>> var(’x’)
>>> f = (2*x + 1) / (x**3 - x)
>>> apart(f)
TP PYTHON - 05
3
Un peu de trigonométrie, à présent. Voici encore un exemple de simplification non automatique :
>>> sin(x)**2 + cos(x)**2
>>> simplify(_)
Le développement d’expressions trigonométriques usuelles se fait avec une fonction spécifique
(expand_trig) :
>>> expand(sin(3*x))
>>> expand_trig(sin(3*x))
Pour terminer cette première section, un mot sur la substitution d’expressions. On peut remplacer,
au sein d’une expression, chaque occurrence d’une sous-expression par une autre. On dispose pour
cela de la méthode subs.
Exemple :
>>> var(’x,y,z’)
>>> e = x + y
>>> e.subs(x, z**2)
[Qu. 1] Pour sympy, le nombre complexe i est noté I. Utiliser la fonction expand pour obtenir la
version simplifiée de l’expression :
x + y + z x + wy + w2 z x + w2 y + wz
√
−1 + i 3
. On définira w de deux façons possibles
où w désigne
2
>>> w = (-1 + I * sqrt(3)) / 2
ou bien :
>>> w = -1/2 + I * sqrt(3)/2
Quelle est la différence de comportement de sympy ? Comment peut-on l’expliquer ?
[Qu. 2] Avant d’exécuter le petit script ci-dessous, essayer de prévoir le résultat.
from sympy import *
var(’x’)
e = x
for n in range(1,4):
e = e.subs(x, (x,x))
print(e)
[Qu. 3] On rappelle que le n−ème polynôme de Tchebychev Tn est caractérisé par :
∀x ∈ R, Tn (cos (x)) = cos (nx)
1
1
Conjecturer une formule simplifiée pour Tn
x+
.
2
x
[Qu. 4] Ont dit que deux polynômes P et Q (à coefficients réels) commutent lorsque :
∀x ∈ R, P (Q (x)) = Q (P (x))
Les polynômes suivants commutent-ils ?
5
P (x) = x2 + x + 1 ,
Q (x) = x2
TP PYTHON - 05
4
On utilisera la méthode subs et la fonction (ou la méthode) expand.
Même question pour les polynômes de Tchebychev T7 et T8 .
calcul numérique
On a eu l’occasion de constater les imprécisions, inhérentes au type float, qui surviennent rapidement
dans certains calculs.
sympy apporte une amélioration très appréciable (avec une classe qui prolonge la classe float) : il
s’agit du calcul numérique en précision arbitraire.
Un exemple en dira plus que de longs discours :
>>> pi
>>> pi.evalf()
>>> pi.evalf(100)
La méthode evalf peut être appliquée à toute expression représentant un nombre réel (ou complexe).
Par défaut, 15 chiffres significatifs sont utilisés, mais on peut demander la précision que l’on veut (les
seules limitations sont le temps de calcul et la mémoire utilisée).
On peut donc, sans se fatiguer trop, calculer la 10 000−ème décimale de π :
>>> approxPi = pi.evalf(10000)
>>> str(approxPi)[-1]
# si s est une chaîne, s[-1] est son dernier caractère
Le nombre π n’est pas la seule constante mathématique prédéfinie par sympy. Sans être exhaustif,
signalons au moins les nombres e et i :
>>> E.evalf()
>>> expand((1+I)*(2-3*I))
La méthode evalf peut s’appliquer à des expressions arbitrairement compliquées :
>>> ((pi + sqrt(2))**(1 + exp(-1))).evalf(30)
sommes et produits
Pour calculer
10
X
k, on n’a pas besoin de sympy. On peut utiliser la fonction sum (prédéfinie à l’ouver-
k=1
ture de la session Python) :
>>> sum(k for k in range(1,11))
Résultat : 55
Pour calculer
10
X
1
k=1
k
, on peut faire de même :
>>> sum(1/k for k in range(1,11))
Mais cette fois, le résultat (2.8289682539682537) est approché (la faute au type float).
Pour obtenir le résultat exact (un nombre rationnel, écrit sous la forme d’une fraction irréductible),
une solution simple consiste à abandonner la fonction sum au profit de la fonction summation. Celle-ci
permet de calculer :
î des sommes finies, purement numériques :
>>> var(’k,n’)
>>> summation(1/k, (k,1,10))
# noter la syntaxe pour les bornes de la somme
TP PYTHON - 05
5
î des sommes finies, non purement numériques, pour lesquelles une formule sommatoire est cherchée :
>>>
>>>
>>>
>>>
summation(1/k, (k,1,n))
summation(k*factorial(k),(k,1,n))
summation(k**2, (k,1,n))
factor(_)
î et des sommes de séries :
>>> summation(1/k**2, (k,1,oo))
# le symbole
∞ est obtenu avec deux ’o’
Bien entendu, on ne sait pas toujours trouver de formule sommatoire et on ne sait pas non plus
calculer explicitement la somme de n’importe quelle série convergente. En pareil cas, le résultat est
laissé sous forme “non évaluée” :
>>> summation(factorial(k), (k,1,n))
>>> summation(1/(k**2*log(k)),(k,2,oo))
Pour calculer des produits, l’analogue de summation est product :
>>> product(sin(k), (k,1,10))
>>> _.evalf(30)
>>> product(k, (k,1,n))
[Qu. 5] Vérifier avec sympy l’identité :
?
∀n ∈ N ,
n
X
k=1
 n 2
X 
k
k = 
3
k=1
On pose maintenant :
Sn,p =
n
X
kp
k=1
de sorte que la formule précédente s’écrit Sn,3 = Sn,1 2 . Calculer et simplifier avec sympy, pour
diverses valeurs de p, l’expression :
!
p
X
p+1
An,p =
Sn, j
j
j=0
Les coefficients binomiaux se calculent avec la fonction binomial. Par exemple :
>>> binomial(10,3)
>>> (10*9*8) // factorial(3)
Conjecturer puis démontrer un résultat général concernant An,p .
[Qu. 6] On note, pour tout n ∈ N et pour tout x ∈ R :
n Y
k
Pn (x) =
1 + x2
k=0
Ecrire une fonction produit(n) qui renvoie l’expression développée de ce produit. On procédera de
deux façons : d’une part, avec la fonction product (cf. ci-dessus) et d’autre part en écrivant une boucle.
Conjecturer puis démontrer une formule générale.
Téléchargement