Processing math: 100%

Jul 26, 2025

Wiki

Python

Aide

edit SideBar

Search

Sympy Complexes Et Fractales


Pré-requis

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 :

Premier contact avec les complexes

Dans sympy, l'imaginaire pur (dont le carré est égal à -1) est noté I.

Opérations élémentaires

Addition, soustraction

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

Multiplication, puissance

  >>> 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

Quotient

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

Conjugaison

On peut enfin obtenir la partie conjuguée...

  >>> a
  2 + 3*I
  >>> a.conjugate()
  2 - 3*I

Module

On peut calculer le module x2+y2 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 

Equation du second degré

L'une des premières utilisations des complexes est la résolution des équations du second degré, comme x2+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é ax2+bx+c=0 a un discriminant Δ=b24ac...

  • strictement positif, alors les racines sont réelles : b±Δ2a
  • nul, alors on a une racine double : b2a
  • strictement négatif, alors les racines sont complexes conjuguées : b±i|Δ|2a

Travaux pratiques

Créer votre propre fonction, qui reproduit le comportement de la fonction solve :

  1. Demandez à l'utilisateur de saisir son équation du second degré.
  2. Calculez le déterminant.
  3. Retournez la, ou les racines, éventuellement complexes.

Application : M de Mandelbrot

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.

Attach:dd.png Δ

Présentation de la fractale

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.

Travaux Pratiques : détermination du nombre borné d'itérations

  • Créer la fonction nombreIt1(c,borne) telle que
    • le premier paramètre c est un nombre complexe
    • le second paramètre borne est un réel positif
    • la fonction retourne le plus petit nombre n tel que le module de zn est supérieur à la borne. Pour cela, on utilisera la méthode evalf() qui, appliquée à une expression sympy formelle, retourne sa valeur flottante comme dans l'exemple suivant:
  >>> from sympy import *
>>> a = 3+5*I
  >>> abs(a)
  34**(1/2)
  >>> abs(a).evalf()
  5.83095189484530
  • Vérifier la fonction avec nombreIt1(0.5,2), nombreIt1(0.8I,2) et nombreIt1(0.5I,2)
  • Pour éviter le dernier problème, construire la fonction nombreIt(c,borne,itermax) telle que
    • les mêmes autres contraintes que nombreIt1(c,borne) mais
    • itermax est le nombre que la fonction retournera si tous les zi sont de module plus petit que c avec 1in

Plus itermax sera grand, plus le découpage du M de Mandelbrot sera précis, mais plus long sera le temps de calcul.

Tracé de l'image

On utilise le module Image. On commence par créer une nouvelle image M, en niveaux de gris (mode 'L'), de taille 32×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 z0=0, zn+1=z2n+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 25620, et afficher le résultat...

Travaux pratiques : affichage complet

  • Construire le Mandelbrot de 64 sur 64 en 20 niveaux de gris, 40 niveaux de gris...

Problème du temps de calcul

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 :

Travaux Pratiques : recentrer l'image

Il reste un point à améliorer : on ne voit qu'une partie du M. Modifier votre code pour obtenir :

Page Actions

Recent Changes

Group & Page

Back Links