• Aucun résultat trouvé

7 Le format (R,G,B) en hexadécimal

7.1

7.1 Exigences du module graphique « Tk »

La couleur d’un pixel à l’écran est décrite au moyen d’un triplet (R,G,B) où chaque lettre représente un nombre compris entre 0 et 255, respectivement une quantité de rouge, de vert et de bleu (Red, Green, Blue)13.

Le module graphique « Tk », qui est utilisé conjointement à Ruby, exige, comme les langages C et Python d’ailleurs, que ces nombres soient convertis en hexadécimal, en deux caractères (faire précéder d’un zéro si un seul caractère est utilisé) et précédés du caractère#. Le nombre 251 doit donc être traduit en #fb, 36en #24 et72en #ac, par exemple.

Le triplet (251,36,72) doit être converti en#fb24ac. C’est non négociable !

7.2

7.2 Code Ruby

Je n’ai pas eu beaucoup de mérite pour transformer 251 en hexadécimal... Ruby fait le calcul en utilisant un format d’affichage littéral. L’instruction puts "#%02x" % [251] affiche #fb.

Explication : le format d’affichage doit être entre guillemets, le caractère # sera simplement reproduit, le (premier) caractère%fait référence à la valeur qui sera passée comme paramètre à la fin du format,02représente le nombre de caractères de sortie,xest le code pour l’hexadécimal.

Le second caractère % introduit le paramètre qui suit, et qui doit être encadré de crochets rectangulaires.

Pour transformer le triplet (251,36,72) en code hexadécimal, on utilise le format de sortie

"#%02x%02x%02x" % [251,36,72].

Il reste à automatiser ce calcul à l’aide d’une fonction dont voici le code :

def rgbhexa(r,g,b)

"#%02x%02x%02x" % [r,g,b]

end

La fonction a été appelée rgbhexa; on lui passe 3 paramètres via des variables nommées r, g et b censées contenir des nombres compris entre 0 et 255 ; la fonction renvoie une chaîne de 7 caractères qui représente la couleur d’un pixel.

rgbhexa(251,36,72) renvoie #fb24ac

Rassurez-vous, le plus compliqué est passé.

13. Avec l’aide de l’analyse combinatoire, on obtient 16 777 216 couleurs.

8

8 « Vitesse d’échappement » d’un complexe

Le principe de base de « calcul » d’un ensemble fractal deJulia,DouadyouMandelbrotest d’appliquer à un nombre complexe initial (un point du plan) une infinité14 de transformations (simples) et de regarder ce qu’il advient du module. Dans la première partie, on explique que s’il dépasse 2, le module deviendra de plus en plus grand, on dit alors que le complexe s’« échappe », et le complexe initial ne fait pas partie du fractal ; on lui attribue dans ce cas un pixel d’une couleur donnée. Dans le cas contraire, on lui attribue un pixel d’une autre couleur. Voici un extrait du code (voir page 58), qui calcule l’ensemble de Mandelbrot.

...

c=convert(a,b) z=Complex(0,0)

for k in 1..300 # nb itérations z=z**2+c

Le test sur le module du complexe (z) n’est réalisé qu’après les 300 itérations.

Dans le code ci-après, on sort de la boucledès quele module dépasse 2. La valeur du compteur k pour laquelle cela se produit est utilisée dans une formule de calcul de la couleur.

L’instructionbreakpermet de sortir de la boucle ; l’opérateur%255calcule le reste de la division euclidienne du calcul qui précède par 255 (car les codes de couleur doivent être compris entre 0 et 255).

Par exemple, si le module s’échappe à partir de la 15e itération, le pixel aura une couleur (R,G,B) qui vaut (150%255,300%255,450%255) = (150,45,195).

for k in 1..300

14. En pratique, on se contente d’un nombre fini...

L’instruction k.to_r transforme l’entierk en réel.

Remarque importante : pour des raisons esthétiques, et contrairement à la première partie, le fractal est représentée en noir. On s’intéresse ici plus à sa frontière.

Remarquer aussi que le test sur le module du complexe z a été inversé... pour s’intéresser d’abord à l’échappement.

En jouant sur les coefficients multiplicateurs de k, on peut obtenir de jolis effets de couleurs.

En ajoutant la fonction rgbhexa et en modifiant le code qui calcule la matrice image, comme l’encadré ci-dessus, on obtient les figures qui suivent.

À gauche, l’ensemble de Mandelbrot avec x ∈[−2,1] et y ∈ [−1.5,1.5]; à droite, le même ensemble, mais avec les coefficients multiplicateurs respectifs 25, 5 et 2.

Rappelons que le couple (x, y) représente la coordonnée d’un point du plan (un complexe) où x∈[Xmin, Xmax]et y∈[Y min, Y max].

On peut maintenant modifier les intervalles, ce qui correspond à faire un zoom sur l’une ou l’autre partie du fractal.

Sur les deux images précédentes, les flèches indiquent la région du plan sur laquelle on a fait un zoom pour obtenir les images suivantes.

-0.1475 -0.0975 0.9925

1.0925

coefficients multiplicateurs 10, 20 et 30

0.2375 0.4075

-0.08 0.09

coefficients multiplicateurs 3, 20 et 6

La seule limite maintenant est celle de l’imagination...

Imaginons l’ensemble défini par









z1= 0 zn+1=z7n+c

dont voici une représentation, ainsi qu’un zoom sur la région pointée par la flèche.

-1.5 1.5

-1.5 1.5

coefficients multiplicateurs 6, 6 et 30

-0.0275 0.0725

1.025 1.125

coefficients multiplicateurs 20, 9 et 9

Dans l’image de droite, on a modifié les paramètres de calcul des couleurs... pour varier les plaisirs.

9

9 Les ensembles de Julia

Un ensemble deJuliaest l’ensemble des affixesztels que|zn|<2après une infinité d’itérations de la forme zn+1=z2n+zczc est un complexe constant prédéfini.

Voici le code Ruby qui tient compte de la gestion des couleurs, comme expliqué précédemment pour l’ensemble de Mandelbrot.

require ’complex’ ; require ’tk’

# taille écran et taille fenêtre pour z=x+yi

Ecran=400;Xmin=-1.5;Xmax=1.5;Ymin=-1.5;Ymax=1.5

# ---root = TkRoot.new(:title => "Julia")

image = TkPhotoImage.new(:height => Ecran, :width => Ecran) label = TkLabel.new(root) ; label.image = image ; label.pack

#

---# conversion de (a,b) dans [1--Ecran,1--Ecran]

# en (x,y) dans [Xmin--Xmax,Ymin--Ymax]

def convert(a,b)

---# conversion code RGB en hexadécimal def rgbhexa(r,g,b)

matrice=matrice + " {"+ligne.join(" ")+ "} "

end

image.put(matrice)

# ---Tk.mainloop

-1.5 1.5 -1.5

1.5

zc= 0.12−0.66i coefficients multiplicateurs

3, 25 et 15

0.1 0.2

0.445 0.545

zc= 0.12−0.66i coefficients multiplicateurs

3, 25 et 15 Le retour du lapin de Douady...

-1.5 1.5

-1.5 1.5

zc=−0.12 + 0.75i coefficients multiplicateurs

20, 5 et 15

-0.3125 -0.2125

0.4075 0.5075

zc=−0.12 + 0.75i coefficients multiplicateurs

20, 5 et 15

Ne boudons pas notre plaisir...

-1.5 1.5

-1.5 1.5

zc=−0.5 + 0.6i coefficients multiplicateurs

5, 20 et 15

0.125 0.225

0.28 0.38

zc=−0.5 + 0.6i coefficients multiplicateurs

5, 20 et 15 Comme pour Mandelbrot, on peut aussi s’amuser à modifier l’exposant.

Voici pour zn+1=z5n+zc.

-1.5 1.5

-1.5 1.5

zc=−0.5 + 0.6i coefficients multiplicateurs

30, 10 et 5

0.25 0.35

-0.6025 -0.5025

zc=−0.5 + 0.6i coefficients multiplicateurs

30, 10 et 5

Un moment de honte étant si vite oublié, pourquoi pas zn+1=−zn9+z3n+zc...

-1.3 1.3

-1.3 1.3

zc=−0.1 + 0.65i coefficients multiplicateurs

30, 10 et 20

-0.8855 -0.3855

-0.349 -0.249

zc=−0.1 + 0.65i coefficients multiplicateurs

30, 10 et 20 Le lecteur se fera un plaisir de trouver la légende du dernier graphique...

10

10 Les limites du format (R,G,B)

On peut dire que les images qui précèdent sont « agréables à regarder ». Mais pour celui qui aime couper les cheveux en quatre, on peut y voir un petit « défaut » : la ligne de séparation des dégradés de couleurs est relativement prononcée.

En voici l’explication pour (par exemple) l’instruction

ligne.push rgbhexa((3*k)%255,(20*k)%255,(15*k)%255) avec k, la valeur de l’échappement, compris entre 1 et 50 (k est le nombre d’itérations de calculs prévus dans le script).

Le tableau suivant ne devrait faire qu’une seule ligne, mais la place manque... il est à lire de gauche à droite et de haut en bas, soit 50 cellules, correspondant chacune à une valeur de k (1, 2, 3, etc.). Chaque cellule est colorée avec le code (R,G,B) calculé à partir des différentes valeur de k et du calcul explicité dans l’instruction ci-dessus : (3,20,15) pour k= 1, (6,40,30) pourk= 2, ... (150,230,240) pour k= 50.

On voit nettement que le dégradé de couleur est loin d’être « continu » ; cela est dû au calcul modulo 255.

Le codage RGB n’est pas l’idéal, en l’état, pour calculer un dégradé « relativement continu » de couleurs. Voici différents codes RGB produisant « du bleu »... Le premier chiffre est la composante R, le second la composante G et la troisième la composante B. Les trois composantes peuvent varier tout en produisant un bleu très semblable.

Essayons autre chose.

11

11 Le format (H,S,L)

La théorie des couleurs n’est pas simple...

Le système (H,S,L) Hue, Saturation, Luminance, en anglais, et (T,S,L) Teinte, Saturation, Luminosité, en français, est basé sur les 3 composantes suivantes :

• Hue (Teinte)

C’est une valeur de couleur, exprimée par un angle (en degrés) sur le cercle chromatique.

Elle reflète notre perception de la couleur, par exemple un pantalon bleu ou rouge.

• Saturation (Intensité)

Elle s’exprime en %, de 0% à 100% et reflète la pureté de la couleur, par exemple un pantalon neuf ou délavé.

• Luminance (Luminosité)

Elle s’exprime aussi en %, de 0% à 100%, du sombre (0%) au clair (100%), 50% étant la luminosité de base. Elle reflète la quantité de lumière, par exemple un pantalon à l’ombre ou au soleil.

On trouve sur le net plusieurs types de graphiques représentant simultanément les 3 compo-santes. En voici un :

Pour appliquer ce modèle de couleur à nos fractals, il faudra calculer un triplet, qui dépend de k, et qui représentera chacune des 3 composantes, dans les unités imposées, à savoir H (un

entier entre 0 et 360), S (un réel entre 0 et 1) et L (un réel entre 0 et 1).

Le tout converti en hexadécimal, puisque c’est une contrainte du langage Ruby.

Cette conversion est loin d’être simple. Sur le site [8] on trouve une recette qui permet de convertir HSL en RGB.

Étant donné la longueur et la complexité, on en a fait une fonction nommée hsl_to_rgb. On lui passe 3 paramètres nommés respectivementh,s etl et contenant respectivement un nombre compris entre 0 et 360, et deux nombres compris entre 0 et 1.

Vient ensuite toute la popote qui calcule trois nombre compris entre 0 et 1... c’est comme ça ! Il faut à la fin convertir ces trois réels en entiers compris entre 0 et 255, ce qui représente le code RGB. La fonction retourne ces 3 nombres, et il faudra encore les convertir en une chaîne hexadécimale, ce que nous avons déjà fait dans les scripts précédents.

Pour faire passer la pilule, voici deux images construites à partir de ce procédé.

-1.6 1.6

-1.5 1.5

J(−0.8−0.18i)

0.534 0.634

0.025 0.125

J(−0.8−0.18i)

Le résultat n’est pas parfait, mais il y a une homogénéité dans la teinte.

Dans le script de calcul de la « matrice-image », nous avons remplacé ligne.push rgbhexa((3*k)%255,(20*k)%255,(15*k)%255)

par

ligne.push "#%02x%02x%02x" % hsl_to_rgb((3*k)%360,0.5,k/50)

def hsl_to_rgb(h,s,l)

Mais tout n’est pas parfait... on ne sait pas supprimer totalement les sauts de couleurs.

Les deux images ci-dessous représentent un zoom sur l’ensemble de Julia J(−0.63 + 0.67i).

Celle de gauche a été créée avec le système RGB et l’instruction ligne.push rgbhexa((10*k)%255,(20*k)%255,(30*k)%255)

et celle de droite avec le système HSL et l’instruction

ligne.push "#%02x%02x%02x" % hsl_to_rgb((5*k)%360,0.9,k/50).

0.44725 0.54725

-0.37675 -0.28675

0.44725 0.54725

-0.37675 -0.28675

Premières impressions... à propos du HSL

On fait au maximum 50 itérations, donckest compris entre 1 et 50. L’image est nettement verte, d’où, le paramètre(5∗k)%360est compris à peu près entre 90 et 150 (voir disque chromatique), et donck (la valeur d’échappement au moment où l’on crée la couleur) est à peu près compris entre 18 et 30.

Conclusion, si on multiplie k par un coefficient pas trop important, on reste dans les mêmes teintes.

Confirmation avec les trois images suivantes, représentant l’ensemble de Julia J(0.35+0.05i) avec x∈[−1.6,1.6] et y∈[−1.5,1.5]. La première avec (k)%360, la seconde avec (10∗k)%360 et la troisième avec (25∗k)%360.

Profitons de notre travail pour admirer d’autres ensembles de Julia...

-1.5 1.5

-1.5 1.5

J(0.1 + 0.613i)

-1.5 1.5

-1.5 1.5

J(−0.12 + 0.75i) - le Lapin

-1.5 1.5

-1.5 1.5

J(0,28−0,02i)

-0,13675 -0,03675

0,86675 0.96675

J(0,28−0,02i)

-1.5 1.5 -1.5

1.5

J(−0,47927−0,5335i)

Toujours dans notre quête d’atténuation des zones de changement de couleurs, nous avons testé une formule non linéaire pour le calcul de la teinte, en l’occurrence un zeste de logarithme.

Les trois images qui suivent représentent un zoom sur l’ensemble J(−0.8−0.18i) avec

x∈[0.1075,0.2075]ety∈[0.2725,0.3725]où l’on a utilisé respectivement, de gauche à droite, (Math.log(k))%360,(12*Math.log(k))%360et(50*Math.log(k))%360pour le calcul de la teinte.

La fonctionMath.log() deRuby est du logarithme népérien.

Le coefficient multiplicateur permet d’avoir un peu plus de choix dans le cercle chromatique.

Quelques modifications dans la formule de récurrence...

zn+1= 1−zn2+2+4zz5n

n+zc avec zc=−0.163 + 0.085i

-3 3

-1.5 1.5

-1.53175 -1.43175

0.075 0.175

Les calculs commencent à prendre un peu plus de temps...

zn+1= 1−zn2+2z4z5n n+zc avec zc=−0.163 + 0.085i

-1.5 1.5

-3 3

-0.0725 0.0275

-0.565 -0.465

12

12 (R,G,B)... le retour

Pour les plus anciens d’entre nous qui s’en souviennent, voilà de nombreuses années déjà (à partir de 1958), l’inspecteur Bourrel, interprété par l’acteur Raymond Souplex, dans la série policière française « Les cinq dernières minutes » a rendu célèbre l’expression Bon Dieu, mais c’est bien sûr ! Et il faut imaginer le geste de la main.

Toujours dans l’optique d’atténuation des changements de couleurs, il suffit, finalement, de faire varier une seule des trois composantes (R,G,B), et de bloquer les deux autres.

Raisonnement avec le bleu (voir image de couverture). Comme nous travaillons avec 50 itérations (k= 1,2,3, ...,50), l’idée est de mémoriser dans un tableau 50 triplets RGB de la forme (0,0,0), (0,0,5), (0,0,10), (0,0,15), ... (0,0,245).

MaisRuby ne permet pas de mettre des triplets dans un tableau. Nous allons donc y mémoriser 150 nombres, le tableau que nous nommerons bleu ressemblera à

bleu[0,0,0,0,0,5,0,0,10,0,0,15,0,0,20, ...,0,0,245]

Il faudra l’interpréter comme suit : bleu[0,0,0

Après un rapide calcul, sikest la valeur de sortie de boucle, la composanteRvaudrableu[3k−3], la composante G vaudra bleu[3k−2] et la composanteB vaudra bleu[3k−1].

Simplissime !

On a bien compris que si on souhaite un dégradé

• de rouges, on créera le tableau rouge[0,0,0,5,0,0,10,0,0,15,0,0, ...,245,0,0];

• de verts, ce sera un tableau vert[0,0,0,0,5,0,0,10,0,0,15,0, ...,0,245,0].

Voici les scripts pour les trois tableaux : rouge=[]

Ces lignes sont à intégrer aux scripts précédents qui ont servi à représenter les fractals de Mandelbrot et de Julia.

Dans ces mêmes scripts, les instructions de calcul de la matrice-image deviennent : if z.abs>2

#ligne.push rgbhexa(0,0,bleu[3*k-1]) ligne.push rgbhexa(rouge[3*k-3],0,0)

#ligne.push rgbhexa(0,vert[3*k-2],0) else

ligne.push rgbhexa(0,0,0) #noir end

Il faut évidemment en choisir une des trois, selon la couleur souhaitée, et placer un symbole de commentaire # devant les deux autres.

-1.6 1.6

-1.5 1.5

J(−0.8−0.18i)

-0.554 -0.454

-0.1775 -0.0775

J(−0.8−0.18i)

J(−0.63 + 0.67i)

Et si on souhaite autre chose que du rouge, du vert, du bleu ?

Le magenta a pour code RGB le triplet (255,0,255), c’est-à-dire « pas de vert ». Il suffit donc de faire varier la première et la troisième composante, et de bloquer la seconde à 0.

magenta=[]

for k in 0..49 r=5*k

g=0 b=5*k

magenta.push r magenta.push g magenta.push b end

0.222 0.322

0.535 0.635

J(−0.75 + 0.0i) if z.abs>2

ligne.push rgbhexa(magenta[3*k-3],0,magenta[3*k-1]) else

ligne.push rgbhexa(0,0,0) #noir end

13

13 (H,S,L)... le retour aussi

On peut utiliser le même principe du tableau de couleurs en utilisant les trois paramètres H, S et L, ce qui permettra de choisir aisément la couleur, en fixant le paramètre H à partir de la roue chromatique.

Dans le premier exemple qui est développé, on a fixé H à 80 (dans le vert), S a été fixé à 0.9, et on a fait varierL (la luminosité) aveck, la valeur de sortie de boucle.Lvarie en théorie dans l’intervalle[0,1], mais après plusieurs essais, c’est dans l’intervalle[0.5,1]que les résultats sont les plus jolis. Voici les scripts qui calculent le tableau des couleurs puis la matrice-image :

coul=[]

Le tableau a été nommé coul.

Les coefficients doivent être décimaux, d’où le 80.0 et k.to_r qui transforme l’entierk en réel.

if z.abs>2

Voici un autre exemple avec H = 220.0 (plutôt dans le bleu) ; il n’y a qu’une seule ligne à modifier dans le script pour changer de couleur.

-1.6 1.6

-1.6 1.6

J(−0.9 + 0.12i)

0.486 0.586

-0.146 -0.046

J(−0.9 + 0.12i)

Dans la vue d’ensemble du fractal, on a l’impression que la couleur « extérieure » est uniforme.

C’est en faisant un zoom sur la frontière que l’on profite plus du dégradé uniforme de couleurs.

Et pour terminer, comme dirait John Lennon, Imagine...

Jean-Marc Desbonnez Chapitre 3

Bassins d’attraction et fractals de Newton

Dans la continuité des « belles images » que sont les fractals de Julia et Mandelbrot, intéressons-nous à ceux de Newton, qui résultent de la méthode du même nom permettant de calculer des valeurs approchées de racines de fonctions. Pour les dessiner, on utilisera quasi les mêmes scripts que pour les ensembles de Julia et Mandelbrot. La transition est donc facile.

Ce contenu est extrait de la présentation faite au congrès annuel de la SBPBef à Mons en août 2015, par Philippe Tilleuil et Jean-Marc Desbonnez, intitulée « De Newton à Ruby, en passant par Monte-Carlo ».

1

1 La méthode de Newton-Raphson

Cette méthode de calcul de valeurs approchées de racines de fonctions est illustrée par le graphique ci-dessous :

• Soit z une solution de l’équation f(x) = 0 (appeléeracine ou zéro).

• Soit a0 une valeur approchée dez et T0 la tangente àf(x) au point (a0, f(a0)).

La tangente a pour équation T0y=f(a0) +f0(a0)·(x−a0)

• Si f0(a0),0 (T0OX), soit a1=T0OX.

0 =f(a0) +f0(a0)·(a1a0) a1=a0f(a0)

f0(a0)

• Et on recommence avec T1 la tangente à f(x) au point

Le lecteur est renvoyé à l’ouvrage [14] pour une analyse plus approfondie de cette méthode.

Cette méthode nécessite le calcul d’une dérivée, qui est simple à programmer une fois calculée...

Illustrons pour le calcul d’une valeur approchée de la racine (réelle) de la fonction f(x) =x3−2x+ 2.

# newton1.rb

# Algorithme de Newton-Raphson

# calcul de zéro(s) d’une fonction

# ---def f(t) # expression analytique de f(x)

return t**3-2*t+2 end

def df(t) # expression analytique de f’(x) return 3*t**2-2

end

# ---a=-2.0 # première valeur approchée de la racine precision=10**(-10) # précision souhaitée

c=0 # compteur d’itérations

while f(a).abs > precision and df(a) > precision a=a-f(a)/df(a)

c=c+1

puts "itération n° #{c} : #{a} " * " #{f(a)}"

end

if df(a) < precision

puts "erreur, tangente horizontale !"

end

Voici les résultats, la convergence est très rapide :

itération an f(an)

1 -1.8 -0.23200000000000065

2 -1.7699481865284974 -0.004849661923670645 3 -1.769292662905941 -2.2814180962171804e-06 4 -1.7692923542386998 -5.053735208093713e-13

Remarque: on peut s’affranchir du calcul de la dérivée en utilisant la méthode ditede la sécante

Mais notre objectif n’est pas ici de comparer les deux méthodes.

Un autre exemple : si on applique le même script pour f(x) = x2−3, après avoir adapté la définition de la fonction et celle de sa dérivée, on obtient le résultat suivant :

la suite a0, a1, a2, . . . , an, . . . converge vers √

En particulier si k=2, on retrouve la formule de l’algorithme deHéron d’Alexandrie pour calculer une valeur approchée de √

2.

• En choisissant initialement a0>0, la suite tend vers √

k, tandis que pour a0 <0, la suite

On dit queR est lebassin d’attractionde−

k tandis queR+ est le bassin d’attractionde√ k.

Voilà, le mot est lâché.

Ici s’écoulent quelques ml d’encre mathématique (dérivée d’une fonction à valeurs complexes, fonction holomorphe, théorème de Cayley, etc. ) mais n’en retenons que la conclusion :

même combat dans C!

2

2 Valeur approchée de racines complexes

Appliquons la même méthode deNewton pour évaluer les racines réelles ou complexes d’une fonction polynôme. Par rapport au script précédent, il faut charger la classecomplex qui permet d’intégrer les calculs avec des nombres complexes, et aussi de choisir un nombre complexe comme valeur initiale de la série des an.

Dans le plan complexe il n’y a plus de tangente parallèle à l’axe des abscisses, et plutôt que d’arrêter les itérations en fonction d’une précision souhaitée, simplifions, et faisons d’office 15 itérations, par exemple.

Voici le script pour la fonction f(x) = x3x−1 dont la seule racine réelle est le nombre de Padovan, dit aussi lenombre de plastique, cousin du nombre d’or. Et il y a aussi deux racines complexes.

f(x) =x3x−1

# newton2.rb

# Algorithme de Newton-version complexe

# ---def f(z) # expression analytique de f(z)

return z**3-z-1 end

def df(z) # expression analytique de f’(z) return 3*z**2-1

end

# ---require ’complex’

z=Complex(14.0,-3.0) # valeur approchée d’une racine for c in 1..15

z=z-f(z)/df(z)

puts " #{c} & #{z} & #{f(z)}"

end

Pour le premier calcul, on a choisi z = 14−3i comme valeur approchée de départ. Détail technique, il faut le définir en utilisant des expressions décimales (14.0 et −3.0) sinon les résultats sont affichés sous forme fractionnaire.

Après chaque itération, on affiche le numéro de celle-ci, le terme correspondant de la suite et son image par la fonction f(x).

it. an f(an)

1 9.350014850014851-1.996064746064746i 695.295178435801-513.5556391278776i 2 6.259480571787746-1.3243077664657334i 205.06037185281932-152.01662639241306i 3 4.214688173095701-0.8721673945359095i 60.03529550235037-44.942884591769015i 4 2.877862158131402-0.5630506999077562i 17.21978080488209-13.24815826697671i 5 2.0324737479123796-0.34339569901305617i 4.644561129150352-3.8717617824856787i 6 1.5483536871596757-0.17631364615347572i 1.0192694125489945-1.0862879306264537i 7 1.347857892100318-0.05204926110168309i 0.08986915817910601-0.2314866719104863i 8 1.322912130599644-0.0023003879516343625i -0.007709235733142528-0.00977730262009142i 9 1.3247160358013998+7.75534362921224e-06i -8.194475053846517e-06+3.30735759159890e-05i 10 1.3247179571921375-2.77724437160376e-11i -2.243563113069058e-10-1.1843927991545276e-10i 11 1.324717957244746+2.723104425918709e-21i 2.220446049250313e-16+1.1613040993788088e-20i 12 1.324717957244746+0.0i 2.220446049250313e-16+0.0i

13 1.324717957244746+0.0i 2.220446049250313e-16+0.0i

Après 13 itérations, on a atteint la limite de précision de Ruby. En prenant z = 14−3i comme valeur approchée de départ, on atteint une valeur approchée de la racine réelle, à savoir 1.324717957244746.

Difficile (impossible ?) de prévoir ce qu’il faut prendre comme valeur de départ pour atteindre l’une ou l’autre racine complexe. Il faut faire quelques essais...

Voici les résultats pour z=−1 +i.

it. an f(an)

1 -0.7837837837837838+0.7027027027027026i 0.46336840858389405+0.24535565514382163i 2 -0.6860940125061868+0.5813564402679697i 0.05878092360516396+0.043136456804783174i 3 -0.663332538306328+0.5625179170617981i 0.0011473459884971948+0.002027180756943414i 4 -0.6623598681149466+0.5622788203407061i -9.83272774979227e-07+2.425032089248269e-06i 5 -0.6623589786212623+0.5622795120614086i -2.6970647937218928e-12-1.917688230435033e-12i 6 -0.662358978622373+0.5622795120623012i 0.0+1.1102230246251565e-16i

7 -0.662358978622373+0.5622795120623012i 0.0+1.1102230246251565e-16i

Et pour z=−2−2i.

it. an f(an)

1 -1.3882149046793761-1.317157712305026i 4.938190171992318-4.012743922849822i 2 -1.0056581666679723-0.8818042821326988i 1.3345228281389017-1.1079573218718008i 3 -0.7840437818922517-0.6434308091847954i 0.27586265950842126-0.27678511347928136i 4 -0.6823785983494443-0.5656551483979103i 0.019648785179123607-0.04353050530359115i 5 -0.6626840006725133-0.5619585128845724i -0.0005121403186956197-0.0009288522562700408i 6 -0.6623587667502647-0.5622794120148417i -3.575348100914866e-07+4.1018449603580365e-07i 7 -0.6623589786224325-0.5622795120622854i 2.220446049250313e-15-1.4299672557172016e-13i 8 -0.662358978622373-0.5622795120623013i 0.0+0.0i

9 -0.662358978622373-0.5622795120623013i 0.0+0.0i

Le compte est bon, on a une valeur approchée des trois racines. Et les deux racines complexes sont conjuguées, c’est rassurant...

3

3 Bassins d’attraction

Méthode

Chaque complexex+yi dans une fenêtre fixée x∈[Xmin, Xmax]et

y ∈ [Y min, Y max] est pris comme valeur approchée de départ pour une série d’itérations de Newton. Selon la racine ainsi atteinte, on le représente avec l’une ou l’autre couleur.

Voici le résultat.1

-5 5

-5 5

20 itérations

0.2 0.3

-0.05 0.05

20 itérations

1. En version belge...

0.24 0.26 -0.1

0.1

20 itérations

0.24 0.26

-0.1 0.1

200 itérations

En noir, le bassin de la racine 1.324717957244746 + 0i (réelle),

en jaune, le bassin de la racine −0.662358978622373−0.5622795120623013i, et en rouge, le bassin de la racine −0.662358978622373 + 0.5622795120623013i.

Les zones blanches dans les graphiques correspondent à des valeurs initiales qui n’aboutissent à aucune des trois racines...car le nombre d’itérations (20 pour les trois premières images) n’était pas suffisant. En passant à 200, les zones blanches (visibles) sont estompées.

Pour la suite, nous opterons donc pour 200 itérations. Les calculs étant sensiblement plus longs (32 millions exactement, 400×400×200, matrice image 400×400 pixels et 200 itérations par pixel), cela nous laisse un peu de temps pour un petit café...

Le script

Par rapport à celui qui a servi à dessiner les fractals de Juliaet de Mandelbrot, il y a peu de modifications, hormis les définitions de la fonction et de sa dérivée, celle des trois racines, et de la création de la matrice-image.

# newton3.rb

# Algorithme de Newton-version complexe

# Bassin d’attraction

#

---def f(z) # expression analytique de f(z) return z**3-z-1

end

def df(z) # expression analytique de f’(z) return 3*z**2-1

# taille écran et taille fenêtre pour z=x+yi Ecran=400

Xmin=0.24;Xmax=0.26;Ymin=-0.01;Ymax=0.01 precision=10**(-15)

#

---root = TkRoot.new(:title => "bassin Padovan")

image = TkPhotoImage.new(:height => Ecran, :width => Ecran) label = TkLabel.new(root)

label.image = image label.pack

#

---# conversion (a,b) dans [0,800]

# en (x,y) dans [Amin/Bmin,Amax/Bmax]

def convert(a,b)

---# conversion code RGB en hexadécimal def rgbhexa(r,g,b)

"#%02x%02x%02x" % [r,g,b]

end

matrice= ""

for b in 1..(Ecran) ligne=[]

for a in 1..(Ecran) z=convert(a,b)

for k in 1..200 # 200 itérations newton z=z-f(z)/df(z)

matrice=matrice + " {"+ligne.join(" ")+ "} "

end

image.put(matrice) Tk.mainloop

Dans le document Raconte-moi des histoires... de fractals (Page 61-90)

Documents relatifs