Plutôt que de réinventer la roue, on utilise le module de calcul formel sympy qui nous permettra d'avoir accès aux nombres complexes.
Dans un terminal, tapez ce qui suit :
wget http://sympy.googlecode.com/files/sympy-0.6.5.tar.gz tar zxvf sympy-0.6.5.tar.gz cd sympy-0.6.5
Ensuite, nous vous conseillons de créer un répertoire dans votre home, au nom de python par exemple, qui contiendra l'ensemble des modules, non-installés à l'IUT, que vous utiliserez :
mkdir ~/python
Reste alors à y copier la bibliothèque sympy :
cp -R sympy ~/python
Reste à tester le tout...
cd ~/python python >>> from sympy import * >>> I I >>> I**2 -1
On a donc bien notre imaginaire pur !
Chez vous, vous pouvez installer sympy, et tout autre module, à sa place normale dans votre système, en tapant la commande (dans le répertoire sympy-0.6.5) :
sudo python setup.py install
Liens sympy :
Dans sympy, l'imaginaire pur (dont le carré est égal à -1) est noté I.
Définissons deux complexes a et b, et montrons comment réaliser les opérations élémentaires avec :
>>> a=2+3*I >>> b=5-2*I >>> a+b 7 + I >>> a-b -3 + 5*I
>>> a*b (2 + 3*I)*(5 - 2*I)
Demandons à sympy de développer l'expression :
>>> expand(a*b) 16 + 11*I
La puissance ne pose aucun problème :
>>> a 2 + 3*I >>> a**5 (2 + 3*I)**5 >>> expand(a**5) 122 - 597*I
Passons au quotient :
>>> a/b (2 + 3*I)/(5 - 2*I)
On peut en demander la simplification :
>>> simplify(a/b) 4/29 + 19*I/29
On peut enfin obtenir la partie conjuguée...
>>> a 2 + 3*I >>> a.conjugate() 2 - 3*I
On peut calculer le module $\sqrt{x^2+y^2}$ du complexe $x+iy$, avec la fonction abs :
>>> b=2+3*I >>> abs(b) 13**(1/2)
Ce qui donne bien la valeur souhaitée. On rappelle que la puissance 1/2 est la racine carrée ; pour s'en convaincre :
>>> pprint(abs(b)) ⎽⎽⎽⎽ ╲╱ 13
L'une des premières utilisations des complexes est la résolution des équations du second degré, comme $x^2+2x+3$ :
>>> x = Symbol('x') >>> solve(x**2+2*x+3,x) [-1 + I*2**(1/2), -1 - I*2**(1/2)]
On rappelle en effet que si une équation du second degré $ax^2+bx+c=0$ a un discriminant $\Delta = b^2-4ac$...
Créer votre propre fonction, qui reproduit le comportement de la fonction solve :
Le but de ce qui suit est de représenter la fractale de Mandelbrot.
On rappelle qu'au point du plan cartésien de coordonnées $(x,y)$, on peut associer le complexe $x+iy$.
Pour chaque point $c = x+iy$ du plan complexe, on regarde le nombre d'itérations nécessaires pour que la suite récurrente
$z_0 = 0$ $z_{n+1} = z_n^2+c$
dépasse, en module, une certaine limite fixée. La couleur du pixel en position $c$ dépendra de ce nombre d'itérations.
>>> from sympy import *
>>> abs(a) 34**(1/2) >>> abs(a).evalf() 5.83095189484530
Plus $itermax$ sera grand, plus le découpage du M de Mandelbrot sera précis, mais plus long sera le temps de calcul.
On utilise le module Image. On commence par créer une nouvelle image M, en niveaux de gris (mode 'L'), de taille $32\times 32$ ;
>>> From PIL import Image >>> monImage = Image.new('L',(32,32)) >>> monImage.show(command = 'eog')
On parcours alors chaque pixel $(k,l)$ de l'image, en regardant à chaque fois le nombre d'itérations nécessaire à la suite $z_0 = 0$, $z_{n+1} = z_n^2+c$ ($c=k+il$) pour dépasser, en module, 2.
Ce nombre d'itération, tronqué à la valeur 20, est le niveau de gris du pixel $(k,l)$...
>>> for k in range(32): ... for l in range(32): ... couleur = nombreIt(k/32.+I*l/32.,2,20) ... monImage.putpixel((k,l),couleur) ... print k, ...
On a donc réalisé le M de Mandelbrot. Seulement, chaque couleur de pixel va de 0 à 20, avec 256 niveaux de gris possibles. On va donc faire une homothétie sur ces niveaux de gris : les multiplier par $\frac{256}{20}$, et afficher le résultat...
Sympy est pour l'instant trop lent pour exécuter une telle quantité de calculs. Dans ce qui suit, on ne fait plus des calculs complexes, mais on utilise les coordonnées des pixels:
def nombreIt(c,borne,itermax): n,z=0,[0,0] while z[0]**2+z[1]**2<borne**2 and n<itermax: z=[z[0]**2-z[1]**2+c[0],2*z[0]*z[1]+c[1]] n+=1 return n taille=512 monImage = Image.new('RGB',(taille,taille)) for k in range(taille): for l in range(taille): couleur = nombreIt([k/float(taille),l/float(taille)],2,50)/50.*256 monImage.putpixel((k,l),(couleur,0,0)) monImage.show(command = 'eog')
On en a profité pour changer la couleur et la taille de l'image, et pour augmenter le nombre d'itérations (50) pour améliorer l'approximation :
Il reste un point à améliorer : on ne voit qu'une partie du M. Modifier votre code pour obtenir :