Arc et MutexLes ensembles de Julia (du mathématicien français Gaston Julia, 1893-1978) sont des objets fractals du plan complexe (plus sur les complexes à la fin du document). Dans ce contexte, le mot fractal signifie que ces objets ont une dimension fractionnaire et présentent des invariances d’échelle. Pour définir les ensembles de Julia, on considère la famille de fonctions complexes où .
On dénote , l’ensemble des points , tels que la suite des itérés est bornée: où est défini par L’ensemble de Julia est le bord de . En d’autres termes, s’il existe tel que . Dans ce TP, nous considérons .
Les ensembles de Julia ont quelques propriétés importantes
Comme est inclus dans le disque de rayon centré en 0, on peut affirmer que si et seulement si la suite des itérés sort de ce disque à une itération donnée.
Pour calculer l’ensemble de Julia, , associé à une valeur, , on peut se restreindre au domaine carré . Ce domaine est discrétisé en une grille dont la finesse du maillage déterminera la précision du calcul. La grille peut être stockée sous forme d’un tableau d’entiers. L’élément du tableau correspondant à un donné, contient l’itération, , à partir de laquelle sort du disque de rayon 2. Dans ce TP, on calcule le temps d’évasion pour , pas directement le bord . C’est cette valeur, , que nous souhaitons calculer et afficher dans ce travail.
Le calcul de l’ensemble rempli
associé à
,
se fait sur le carré du plan complexe, dont le coin inférieur gauche est
et supérieur droit
,
carré qu’on discrétise en une grille. Pour chacune des valeurs complexes
de la grille, appelons les
,
on détermine si la suite des itérés
est bornée ou non.
Une bonne heuristique est obtenue en effectuant un certain nombre
d’itérations, nb_iter, pour voir si la suite sort du disque
de rayon 2. Ceci correspond à la condition
Évidemment,
nb_iter représente une borne maximale, car on peut
interrompre l’itération dès qu’on a quitté le disque de rayon 2. En
d’autre termes, on enregistre le
,
tel que
.
Si
on interrompt la boucle et on enregistre ou
.
Pour visualiser les résultats vous pouvez utiliser la crate
image par exemple. Vous pouvez aller sur la
page pour trouver des exemples de valeurs de
et les résultats attendus.
Une fois le calcul de l’ensemble de Julia étant réalisé de façon
séquentielle, il vous reste la partie importante de ce travail pratique:
paralléliser le code en utilisant des threads système. Vous pouvez
essayer différentes stratégies de parallélisation. Par exemple, vous
pouvez spawn un thread par pixel ou un thread par ligne ou
colonne. Une autre façon de paralléliser votre travail est via la crate
rayon que vous pouvez également tester. Selon votre
stratégie, vous aurez peut-être besoin de Arc et de
Mutex pour les accès concurrents à la matrice de pixels que
vous allez créer.
Pour chaque exécution mesurez le temps de calcul de l’ensemble de Julia, même sans rendu formel.
Pour avoir un gain visible pensez à faire des images assez grandes (1000 x 1000 p.ex.).
Mesurez le temps d’exécution en version séquentielle, puis en version parallèle. Faites un petit tableau de mesures pour vous guider (p.ex. 1, 2, 4, 8 threads) et constatez le gain observé.
Comme vous l’aurez compris pour réaliser ce travail il faut réaliser une librairie de manipulation de nombres complexes. Chaque nombre complexe est constitué d’une paire de nombres réels: la partie réelle et la partie imaginaire du nombre. Le type complexe sera donc une structure
struct Complex {
re: f64,
im: f64,
}Ensuite il faut implémenter les règles d’addition, de multiplication entre deux nombres complexes, ainsi que le module d’un nombre complexe.
Soit un nombre complexe. On note ce nombre où est la partie réelle de , la partie imaginaire de , et le nombre imaginaire qui a la super propriété . Avec cette notation, on peut calculer presque comme avec des nombres réels. Ainsi l’addition de deux nombres complexes, , s’écrit Le produit est un peu plus complexe mais s’écrit Finalement le module de s’écrit Comme vous pouvez le voir dans la définition de la structure des nombres complexes, à aucun moment nous n’avons besoin de représenter dans notre structure de données. est nécessaire pour les humains pour qu’ils puissent calculer plus facilement avec les nombres complexes.
Avec ce qui précède vous pouvez implémenter les traits
Add et Mul pour le type Complex,
ainsi que la fonction associée module() et avez en votre
possession tout ce qu’il faut pour écrire le code qui vous permettra de
faire des figures plus incroyables les unes que les autres.