Spe_NSI/102_Fractales/FractaleDeJulia_valentin_moguerou.ipynb

847 lines
110 KiB
Plaintext
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1 style=\"color: indigo\">&emsp; Tracer des fractales de Julia : &emsp;</h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cette fois il s'agit de tracer des fractales, issues **des mathématiques et non de la nature** comme pour les Lsystem. \n",
"Gaston Maurice JULIA est un mathématicien du début du XX eme siècle. Il a travaillé sur les itérations de fonctions complexes. \n",
"Remarque: Il ne disposait pas alors d'ordinateur avec écran graphique pour représenter son travail ;-) \n",
"Dans les années 1970, Benoît MANDELBROT c'est intéressé aux travaux de JULIA et a inventé le terme de fractale. \n",
"Voir: https://fr.wikipedia.org/wiki/Ensemble_de_Mandelbrot\n",
"\n",
"![image](./images/julia.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\"> 1/ Rappel: les équations du second degré : </h3>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La théorie développée par Julia est basée sur les nombres complexes. Ces derniers trouvent leur justification dans la résolution des équations du second degré : \n",
"$a.x² + b.x + c = 0$ \n",
"La résolution d'une telle équation se fait par le calcul de son discriminant : \n",
"$\\Delta = b² - 4.a.c$ \n",
"Le signe de ce dernier nous renseigne sur les solutions de l'équation: \n",
"$\\Delta > 0 \\rightarrow$ l'équation admet deux racines qui sont distinctes: $x_1 = (-b +\\sqrt \\Delta)/2.a$ et $x_2 = (-b -\\sqrt \\Delta)/2.a$ \n",
"$\\Delta = 0 \\rightarrow$ l'équation a pour solution une racine double: $x_1 = -b/2.a$ \n",
"$\\Delta < 0 \\rightarrow$ l'équation n'a pas de solution dans l'ensemble des réels: $\\mathbb{R}$ ... $\\Rightarrow$ mais peut-être dans un autre ensemble, tel que:$\\mathbb{C}$ "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"En résumé: \n",
"![image](./images/Equation2degre.png)\n",
" \n",
"$\\Rightarrow$ Écrire un script permettant à partir d'une équation donnée par l'utilisateur, de préciser si cette équation a des solutions et leurs valeurs."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"L'ensemble des solutions est {2.6666666666666665, -5.0}.\n"
]
}
],
"source": [
"'''Résolution de l'équation du 2° degré '''\n",
"\n",
"from math import sqrt\n",
"\n",
"def solve(a, b, c):\n",
" d = b**2 - 4*a*c\n",
" if d<0:\n",
" return set()\n",
" return {(-b-sqrt(d))/(2*a), (-b+sqrt(d))/(2*a)}\n",
"\n",
"a,b,c = (float(x.strip()) for x in input(\"aX² + bX + c = 0. Entrer a, b, c [format: 'a,b,c']\").split(','))\n",
"print(f\"L'ensemble des solutions est {solve(a,b,c)}.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">2/ Au secours Valentin : c'est quoi un nombre complexe ? De quoi on parle, tu nous expliques ?</h3> \n",
"\n",
"Introduction à l'ensemble des complexes: $\\mathbb{C}$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"'''Les nombres complexes avec Python'''\n",
"\n",
"a = int(input('Saisir la partie réelle du nombre complexe z: '))\n",
"b = int(input('Saisir la partie imaginaire du nombre complexe z: '))\n",
"z = complex(a,b)\n",
"print(f'z = {z} \\n')\n",
"print(f'La partie réelle de z est : {z.real}')\n",
"print(f'La partie imaginaire de z est : {z.imag}i \\n')\n",
"print(f'Le module de z est : {abs(z)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\"> Ce qu'il faut retenir : </h3> \n",
"\n",
"$\\Rightarrow$ Il existe un ensemble $\\mathbb{C}$ appelé ensemble des complexes, dans lequel l'ensemble des réels $\\mathbb{R}$ est inclus \n",
"Un complexe est définit par deux nombres réels : \n",
"le premier représente la partie réel du complexe, le deuxième sa partie imaginaire à laquelle est associée à la lettre i (ou j) : $z = -2 + 3i$ ou encore $z = -2 + 3j$ \n",
"\n",
"**Propriété de l'imaginaire i** : $~i^2 = -1$ (ou encore : $~j^2 = -1$). \n",
"C'est cette dernière propriété qui permet de résoudre le cas $\\Delta < 0$ pour les équations du 2° degré : \n",
"![image](./images/DeltaNegatif.png)\n",
"\n",
"Puisque d'un nombre complexe est constitué de deux parties (partie réelle et partie imaginaire), il est tentant de lui associé un point du plan de tel sorte que : \n",
"- sa partie réelle est portée par l'axe des abscisses (Ox) \n",
"- sa partie imaginaire est portée par l'axe des ordonnées (Oy). \n",
"\n",
"Ainsi au nombre complexe $z = a + bi$ correspond le point M de coordonnées a et b : $M(a, b)$. \n",
"On dit que : **z est l'affixe du point M**. \n",
"\n",
"Application: Utiliser le logiciel ```Geogebra``` (sélectionner le mode **Tableur** => voir menu *Affichage*) pour représenter dans **le plan complexe** les points d'affixe : \n",
"$z_1 = 2 + 3i; ~ z_2 = 1; ~ z_3 = -1i = -i$ (ne pas oublier de cocher dans Géogebra : *Afficher l'objet*).\n",
"\n",
"On constate que la distance du point M (affixe de z) à l'origine est donnée par : $\\sqrt{a^2 + b^2}$. \n",
"Cette distance représente aussi le module du nombre complexe $~z = a + ib$ : \n",
"$|z| = \\sqrt{a^2 + b^2}$\n",
"\n",
"![lien](http://www.jaicompris.com/image/playvideo.png)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">3/ Compléter votre algorithme sur la résolution d'une équation du 2° degré :</br>\n",
" => Ajouter le cas où le discriminant est négatif </h3>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Le point maths, par Valentin\n",
"\n",
"## Théorème d'Alembert-Gauss\n",
"\n",
"Tout polynôme non constant à coefficients complexes admet une racine dans $\\mathbb{C}$.\n",
"\n",
"$\\boxed{\\forall P \\in \\mathbb{C}[X], \\deg P \\geqslant 1, \\exists z \\in \\mathbb{C} \\quad P(z) = 0}$\n",
"\n",
"On peut aussi dire que tout polynôme de $\\mathbb{C}[X]$ peut être factorisé, de la forme :\n",
"\n",
"$\\displaystyle P(X) = a_n\\prod_{k=1}^n (X - a_k)$ (où $n$ est le degré de $P$).\n",
"\n",
"Cela entraîne que la somme des multiplicités des racines distinctes d'un polynôme vaut le degré de ce polynôme.\n",
"\n",
"## Un cas particulier : $\\deg P = 2$\n",
"\n",
"Soit $P = aX^2 + bX + c$ et soit $\\Delta = b^2 - 4ac$.\n",
"\n",
"Soient $\\delta_1$ et $\\delta_2$ les deux racines carrées de $\\Delta$.\n",
"\n",
"Alors $z_1 = \\dfrac{-b-\\delta}{2a}$ et $z_2 = \\dfrac{-b+\\delta}{2a}$ vérifient $P(z_1) = 0$ et $P(z_2) = 0$\n",
"\n",
"Dans le cas où $z_1 = z_2$, on dit que $z_1$ est de multiplicité 2.\n",
"\n",
"Remarquons que $\\delta_1 + \\delta_2 = 0$.\n",
"\n",
"La fonction python sqrt du module cmath associe à un complexe $z$ une de ses deux racines carrées. Notons $\\delta$ une telle racine. Alors $\\{\\delta, -\\delta\\}$ est l'image de $z$ par la multifonction (i.e correspondance) qui à un complexe associe ses racines carrées. C'est aussi la coupe du graphe $\\{(x, y) \\in \\mathbb{C}^2 \\mid y^2 = x \\}$ suivant $\\{z\\}$. L'application $f: z \\mapsto z^2$ n'étant pas injective, la correspondance $f^{-1}$ n'est pas univoque."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{(-0.6180339887498949+0j), (1.618033988749895+0j)}"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'''Résolution d'une équation du second degré dans l'ensemble des complexes'''\n",
"\n",
"from cmath import sqrt\n",
"\n",
"def solve(a, b, c):\n",
" d = b**2 - 4*a*c\n",
" return {(-b-sqrt(d))/(2*a), (-b+sqrt(d))/(2*a)}\n",
"\n",
"solve(1, -1, -1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\"> 4/ Les suites de Julia :</h3> \n",
"\n",
"Une **suite d'éléments de $E$** est une application de $\\mathbb{N}$ dans $E$. Ces suites sont soit définies explicitement, soit définies par récurrence.\n",
"Exemple: $u_{n+1} = u_n * 2 + 3$. On suppose ici que le terme initial est: $u_0 = 1$ :\n",
"- $u_0 = 1$\n",
"- $u_1 = 5$\n",
"- $u_2 = 13$\n",
"- ... \n",
"\n",
"Le calcul d'un terme n d'une suite, avec n très grand, peut-être long et fastidieux. \n",
"$\\Rightarrow$ La technologie numérique et les ordinateurs s'avèrent d'une grande aide pour le calcul des suites. \n",
"- Exemple 1 : La suite de Fibonacci, déjà rencontrée en exercice, pour laquelle l'élément $u_n$ dépend de $u_{n-1}$ et $u_{n-2}$ \n",
"$\\Rightarrow ~f_0 = 0; ~ f_1 = 1 ~~ \\Rightarrow ~ f_n = f_{n-1} + f_{n-2}$ \n",
"\n",
"- Exemple 2 : avec le programme du calcul du Lsystem : \n",
"$\\Rightarrow$ Voir le code ci-dessous : **mettre en évidence** la ligne permettant le ***calcul de la suite*** des termes du Lsystem: à l'aide d'un commentaire."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ordre 0 => A\n",
"ordre 1 => AB\n",
"ordre 2 => ABA\n",
"ordre 3 => ABAAB\n",
"ordre 4 => ABAABABA\n"
]
}
],
"source": [
"def codage_lSystem(chaine: str, ordre: int) -> str:\n",
" \"\"\"\n",
" Prends en entrée une chaîne initiale (l'axiome) et l'ordre souhaité\n",
" Retourne la chaîne obtenue après n applications du L-system\n",
" \"\"\"\n",
" for n in range(ordre): # Itérer le lSystem jusqu'à l'ordre n\n",
" chaine = lSystem_convert(chaine)\n",
" return chaine\n",
"\n",
"def lSystem_convert(chaine: str) -> str:\n",
" \"\"\"\n",
" Prends en entrée une chaîne de caractères\n",
" Retourne la chaîne obtenue après application des règles du L-System\n",
" \"\"\"\n",
" rules = {'A': 'AB', 'B': 'A'} # A compléter : règles\n",
" return ''.join([rules[car] for car in chaine ]) \n",
"\n",
"axiome = 'A'\n",
"for k in range (5): # Pour affichage des générations jusqu'à l'ordre n\n",
" print(f'ordre {k} => {codage_lSystem(axiome, k)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">5/ Les ensembles de Julia : </h3>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Un ensemble de Julia $J(c)$ est défini à partir d'une suite ```complexe```, et consiste à voir si la suite $u_n$ \"s'échappe\" d'un domaine donné, lorsque n augmente. \n",
"Exemple : on considère la suite de Julia telle que: \n",
"- $u_0 = z$\n",
"- $u_{n+1} = u_n ^2 + c$ \n",
"\n",
"Dans laquelle $~z~$ et $~c~$ sont des nombres complexes : $~~z = a + bi~~$ et $~~c = p + qi$ , avec : \n",
"- $~z~\\Rightarrow$ qui représente la valeur initiale de la suite $u_0$ ;\n",
"- $~c~\\Rightarrow$ un paramètre (sous forme *complexe*) de la suite de Julia.\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"u0 = 0.0 + 0.0 i\n",
"(-0.5+0.6j)\n",
"(-0.61+0j)\n",
"(-0.1279+0.6j)\n",
"(-0.84364159+0.44652j)\n",
"(0.012351021977728305-0.1534056855336j)\n",
"(-0.5233807566101395+0.596210566012932j)\n",
"(-0.5815396226356586-0.024090274277615786j)\n",
"(-0.1623920086195465+0.6280188980251884j)\n",
"(-0.8680365718132812+0.396029499397311j)\n",
"(0.09664812561246894-0.08753617798754354j)\n",
"(-0.49832172227226335+0.5830795849484489j)\n",
"(-0.5916572634952607+0.018877554013384867j)\n",
"(-0.1502980445988279+0.5776619161019134j)\n",
"(-0.8111037871043028+0.42635708714134046j)\n",
"(-0.02389101230070656-0.091639696078201j)\n",
"(-0.5078270534285525+0.6043787302124746j)\n",
"(-0.6073853333393171-0.013839739437382148j)\n",
"(-0.13127459523198132+0.6168121095030072j)\n",
"(-0.8632241590762293+0.43805647998161634j)\n",
"(0.05326246915897892-0.1562818731200477j)\n"
]
}
],
"source": [
"def suiteJulia(z: complex, c: complex) -> complex :\n",
" \"\"\"\n",
" Calcul de la suite de Julia: \n",
" En entrée: z et c sont des complexes.\n",
" Retourne un complexe.\n",
" \"\"\"\n",
" u = z\n",
" print(f'u0 = {(u.real)} + {(u.imag)} i')\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" print(u)\n",
"\n",
"z = complex(0, 0)\n",
"suiteJulia(z, complex(-0.5, 0.6))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">6/ Analyse et exploitation des résultats : </h3>\n",
"<h4 style=\"color: SeaGreen\" class=\"fa fa-book\">61/ Mise en place des points dans le plan complexe : <mark style=\"color: DarkBlue\"> => avec Geogebra : </mark></h4>\n",
"\n",
"Examiner les valeurs obtenues en retour à lexécution du code précédent. \n",
"Utiliser le logiciel ```Géogebra``` pour placer directement dans le *plan complexe*, les points obtenus : => tester tout d'abord pour un point, saisie en mode tableur et sans oublier de cocher \"Afficher l'objet\". \n",
"***Remarque*** : *Le mode tableur de ```Géogebra``` accepte de charger des points à partir d'un fichier, .dat par exemple (clic droit).* \n",
"**Cependant cette fonctionnalité dépend de la version de ```Géogebra``` à votre disposition:** *si votre version ne propose pas cette fonctionnalité, vous pouvez réaliser cette partie avec : Matplotlib*. \n",
"**Remarque** : Matplolib est moins adapté, puisqu'il vous faudra vous même mettre en place les points dans le plan complexe, à l'aide de leur partie réelle et partie imaginaire. \n",
"\n",
"Afin de pouvoir charger les points à partir d'un fichier, il faut adapter le code ci-dessus afin d'enregistrer les points dans un fichier ```Julia.dat``` et transformer le type ```complex``` de Python pour l'adapter au type reconnu par ```Géogebra``` : \n",
"$~a+bj \\Rightarrow a+bi~$. \n",
"A voir : l'exercice sur le tracé d'une spirale dans les activités de révision et aussi [ici](https://python.doctor/page-lire-ecrire-creer-fichier-python \"python.doctor: lire ecrire dans un fichier\")."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0j"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\" Saisir ici le code précédent, adapté pour générer un fichier : Julia.dat => et l'importer dans Géogebra \"\n",
"\n",
"def suiteJuliaFichier(z: complex, c: complex) -> complex :\n",
" \"\"\"\n",
" Calcul de la suite de Julia: \n",
" En entrée: z et c sont des complexes.\n",
" Retourne un complexe.\n",
" \"\"\"\n",
" with open('Julia.dat', 'w') as file:\n",
" u = z\n",
" print(f'u_0 = {(u.real)} + {(u.imag)} i', file=file)\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" print(f'u_{i+1} = {(u.real)} + {(u.imag)} i', file=file)\n",
" return z\n",
"z = complex(0, 0)\n",
"suiteJuliaFichier(z, complex(-0.5, 0.6))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h4 ><mark style= \"color: DarkBlue\"> => avec Matplotlib : </mark></h4>\n",
"\n",
"Pour représenter les points avec Matplotlib, il vous faut extraire la partie réel et la partie imaginaire des résultats renvoyé par la fonction ```suiteJulia()```. \n",
"**=> Compléter le code suivant :**"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"u0 = 0.0 + 0.0 i\n"
]
},
{
"data": {
"image/png": "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oqqqKvr27RtHHnlkzJ49OzZs2BA///nPIyLixz/+cZSXl8enP/3p2LFjR9x2223xyCOPxH//93/nc5oAAAAtlteIevbZZ+Pkk09uuD9r1qyIiLjgggtiwYIFUV1dHevXr294fOfOnXHFFVfEhg0bolevXvGZz3wmHn744UbPAQAA0J4KsizL2nsSram2tjZKSkoil8tFcXFxe08HAABoJ/lqg4N+YQkAAICDiYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIIKIAAAASiCgAAIAEIgoAACCBiAIAAEggogAAABKIKAAAgAQiCgAAIIGIAgAASCCiAAAAEogoAACABCIKAAAggYgCAABIkNeIevzxx2Py5MkxcODAKCgoiAceeGC/+yxdujRGjRoVhYWFceyxx8aCBQvyOUUAAIAkeY2o7du3x/Dhw+Omm25q0fh169bFGWecESeffHJUVVXF5ZdfHl/72tfi97//fT6nCQAA0GKH5PPJTzvttDjttNNaPH7+/PlRXl4e119/fUREfOpTn4onnngibrjhhpg4cWK+pgkAANBiB9V7oiorK2PChAmNtk2cODEqKyv3uU9dXV3U1tY2ugEAAOTLQRVRNTU1MWDAgEbbBgwYELW1tfHuu+82uc+8efOipKSk4TZo0KC2mCoAANBFHVQRdSBmz54duVyu4fb666+395QAAIBOLK/viUpVWloaGzdubLRt48aNUVxcHIceemiT+xQWFkZhYWFbTA8AAODgOhNVUVERS5YsabRt8eLFUVFR0U4zAgAAaCyvEbVt27aoqqqKqqqqiHhvCfOqqqpYv359RLx3Kd7UqVMbxl9yySXxxz/+Mb7zne/Eyy+/HD/96U/j17/+dXzzm9/M5zQBAABaLK8R9eyzz8bIkSNj5MiRERExa9asGDlyZFx99dUREVFdXd0QVBER5eXl8dvf/jYWL14cw4cPj+uvvz5uu+02y5sDAAAHjYIsy7L2nkRrqq2tjZKSksjlclFcXNze0wEAANpJvtrgoHpPFAAAwMFORAEAACQQUQAAAAlEFAAAQAIRBQAAkEBEAQAAJBBRAAAACUQUAABAAhEFAACQQEQBAAAkEFEAAAAJRBQAAEACEQUAAJBARAEAACQQUQAAAAlEFAA
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\"Représentation des point dans le plan complexe, avec Matplotlib :\"\n",
"\n",
"import matplotlib.pyplot as plt\n",
"\n",
"def suiteJulia(u: complex, c: complex) -> 'list[complex]' :\n",
" \"\"\"\n",
" Calcul de la suite de Julia: \n",
" En entrée: z et c sont des complexes.\n",
" Retourne une liste de complexes.\n",
" \"\"\"\n",
" u = z\n",
" s = [u]\n",
" print(f'u0 = {(u.real)} + {(u.imag)} i')\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" s.append(u)\n",
" return s\n",
"\n",
"def tracer_les_points(listePoints):\n",
" \"Pour tracer les points :\"\n",
" plt.figure(figsize=(10,10))\n",
" plt.xlim([-2, 2])\n",
" plt.ylim([-2, 2])\n",
" plt.scatter([z.real for z in listePoints], [z.imag for z in listePoints])\n",
" plt.show()\n",
" plt.close()\n",
"\n",
"u = complex(0, 0)\n",
"tracer_les_points(suiteJulia(u, complex(-0.5, 0.6)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h4 style=\"color: SeaGreen\" class=\"fa fa-book\">62/ Le point d'affixe z = 0 + 0i appartient-il à l'ensemble de Julia J(c) ? </h4>\n",
"<h4><mark style=\"color: DarkBlue\"> => avec Geogebra : </mark></h4>\n",
"\n",
"Pour le savoir : tracer dans ```géogebra``` un cercle de centre 0 et de rayon 2. Si les points de la suite sont dans ce cercle, c'est donc que le point z appartient à l'ensemble de Julia (du moins en ce qui concerne les vingts premiers termes de la suite). \n",
"\n",
"Essayer maintenant la suite, pour laquelle: $~z = 0.239 + 0.2i~$ et $~c = -0.5 + 0.6i$ \n",
"Cette fois vous devriez constater que les dernières valeurs de la suite \"s'échappent\" du cercle. \n",
"$\\Rightarrow$ On en déduit que le point M d'affixe $~z = 0.239 + 0.2i~$ n'appartient pas à l'ensemble J(c). \n",
"\n",
"<h4 ><mark style= \"color: DarkBlue\"> => avec Matplotlib : </mark></h4>\n",
"\n",
"Reprendre les étapes décrites ci-dessus en les adaptant à Matplotlib **=> compléter le code ci-dessous:**"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"u0 = 0.0 + 0.0 i\n",
"u0 = 0.0 + 0.0 i\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\"Savoir si un point z appartient à l'ensemble de Julia J(c) :\"\n",
"\n",
"import matplotlib.pyplot as plt\n",
"\n",
"def suiteJulia(u: complex, c: complex) -> 'list[complex]' :\n",
" \"\"\"\n",
" Calcul de la suite de Julia: \n",
" En entrée: z et c sont des complexes.\n",
" Retourne une liste de complexes.\n",
" \"\"\"\n",
" u = z\n",
" s = [u]\n",
" print(f'u0 = {(u.real)} + {(u.imag)} i')\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" s.append(u)\n",
" return s\n",
"\n",
"def tracer_les_points(listePoints):\n",
" \"Pour tracer les points :\"\n",
" plt.figure(figsize=(10,10))\n",
" plt.xlim([-2, 2])\n",
" plt.ylim([-2, 2])\n",
" plt.scatter([z.real for z in listePoints], [z.imag for z in listePoints])\n",
" cercle = plt.Circle((0, 0), 2,fill=False)\n",
" plt.gcf().gca().add_artist(cercle)\n",
" plt.show()\n",
" plt.close()\n",
"\"\"\"\n",
"def cercle_limite():\n",
" cercle = plt.Circle((0, 0), 2,fill=False)\n",
" plt.gcf().gca().add_artist(cercle) #gca = Get Current Axis\n",
" plt.show()\n",
" plt.close()\n",
"\"\"\"\n",
"u = complex(0, 0)\n",
"suiteJulia(u, complex(-0.5, 0.6))\n",
"tracer_les_points(suiteJulia(u, complex(-0.5, 0.6)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h4 style=\"color: SeaGreen\" class=\"fa fa-book\">63/ Savoir si un point appartient à l'ensemble de Julia : </h4>\n",
"\n",
"Pour savoir si un point $M$ d'affixe $z$ appartient à l'ensemble de Julia J(c), on peut se limiter à examiner ***le module $u_n$*** de la suite de Julia : \n",
"D'après la définition du module d'un nombre complexe (distance du point $M$ d'affixe $z = a + jb$, à l'origine $O$ du plan complexe), regarder si un point de la suite \"s'échappe\" du domaine de Julia, limité par le cercle de centre $0$ et de rayon 2, revient à examiner si **le module du complexe $~u_n~$ calculé est supérieur à 2**. \n",
"On peut d'ailleurs démontrer que la suite tend vers l'infini (n'appartient donc pas à J(c)) lorsque justement ses termes $u_n$ sortent du cercle de rayon 2, centré en $O$. \n",
"\n",
"Appliquer cette propriété pour examiner et conclure sur l'évolution de $|u_n|$ pour les valeurs de $~z~$ et du paramètre $~c~$ suivantes :"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"u0 = 0.0 + 0.0 i\n",
"0.7810249675906654\n",
"0.61\n",
"0.6134805701894722\n",
"0.9545214731883868\n",
"0.15390208607399739\n",
"0.7933438443797638\n",
"0.5820383784682888\n",
"0.6486747264540702\n",
"0.9541105042909015\n",
"0.13039724936159686\n",
"0.7670113045268956\n",
"0.5919583427000827\n",
"0.5968942884001868\n",
"0.9163349383334626\n",
"0.0947027685237214\n",
"0.789406084171619\n",
"0.6075429874036964\n",
"0.6306268292602768\n",
"0.9680131344495009\n",
"0.16510879590991473\n"
]
}
],
"source": [
"'''Modifier le code de la fonction suite de Julia afin d'afficher 20 itérations du module de u => abs(u)\n",
"Ceci pour les valeurs suivantes de la suite :\n",
"z = 0 + 0i et c = -0.5 + 0.6i\n",
"z = 0.239 + 0.2i et c = -0.5 + 0.6i\n",
"z = 0.25 + 0.2i et c = -0.5 + 0.6i\n",
"'''\n",
"\n",
"def suiteJulia(z: complex, c: complex) -> complex :\n",
" \"\"\"\n",
" Calcul de la suite de Julia: \n",
" En entrée: z et c sont des complexes.\n",
" Retourne un complexe.\n",
" \"\"\"\n",
" u = z\n",
" print(f'u0 = {(u.real)} + {(u.imag)} i')\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" print(abs(u))\n",
"\n",
"z = complex(0, 0)\n",
"suiteJulia(z, complex(-0.5, 0.6))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">7/ Construction des fractales de Julia : </h3>\n",
"<h4 style=\"color: SeaGreen\">71/ Calculer l'ensemble de Julia : </h4>\n",
"\n",
"**Écrire une fonction ```ensembleJulia```** qui devra itérer 100 fois (ou plus) le calcul de la suite de Julia à partir du point $~M~$ d'affixe $~z~$ et du paramètre $~c~$. \n",
"Cette fonction doit renvoyer : \n",
"- -1 si le point $M$ appartient à J(c) => dans ce cas toutes les itérations donnent un module inférieur à 2;\n",
"- l'indice i du tour de boucle qui correspond au premier terme de la suite supérieur à 2. "
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"def ensembleJulia (z: complex, c: complex) -> int :\n",
" '''Prend une suite de Julia et un point d'affixe z :\n",
" Retourne => -1 si le point est dans l'ensemble J(c): le module de tous les termes est < 2\n",
" Retourne l'indice i du premier terme ayant un module supérieur à 2\n",
" '''\n",
"\n",
" u = z\n",
" print(f'u0 = {(u.real)} + {(u.imag)} i')\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" if abs(u) > 2:\n",
" return i\n",
" return -1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h4 style = 'color: SeaGreen'> 72/ Changement de repère :</h4>\n",
"\n",
"Puisqu'il s'agit de tracer une image à l'écran, nous allons faire en sorte que les points $M$ (de la suite de Julia) appartiennent à l'écran de l'ordinateur. Donc le plan complexe sera représenté par l'écran de l'ordinateur. \n",
"L'écran est constitué de pixels ayant $x$ et $y$ pour coordonnées. Les dimensions de l'image de la fractale seront comprises entre 0 et 400 pixels pour $x$ et pour $y$. \n",
"Les ensembles de Julia intéressant sont pour $z = a + ib$ ayant une partie réelle $a$ et une partie imaginaire $b$ comprises entre -1.25 et +1.25. \n",
"Un changement de repère est donc nécessaire pour faire correspondre la partie du plan complexe pertinente (-1.25 -> +1.25) avec les pixels de notre image fractale (0 -> 400). \n",
"\n",
"![image](./images/ChgntRepere.png)\n",
"\n",
"\n",
"**Établir les équations** pour passer de l'image en pixel, à la valeur de $z$, et **écrire** la fonction ```convert``` correspondante :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def convert(x:int, y:int) ->complex :\n",
" \"Convertit un point du plan (de l'image) de coordonnées x, y en un nombre complexe z = re + img*j\"\n",
" return complex(x/160 - 1.25, y/160 - 1.25)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h4 style = 'color: SeaGreen'> 73/ Gestion des couleurs :</h4>\n",
"\n",
"A chaque point de notre fractale correspond un affixe $z$ utilisé dans la fonction ```ensembleJulia``` pour savoir si ce point appartient ou pas à J(c). \n",
"Nous allons affecter une couleur à ce point, en fonction de sont appartenance ou pas à J(c). Dans ce dernier cas, sa couleur sera fonction du rang du terme pour lequel il s'échappe de J(c). \n",
"*Rappel: la couleur d'un pixel est définie par un triplet de nombres, chacun compris entre 0 et 255.* \n",
"Principe: si n représente le nombre renvoyé par la fonction ```ensembleJulia```:\n",
"- si n=-1 le pixel correspondant est noir.\n",
"- et pour 0< n <100 : \n",
"=> la couleur (n, n , n) donnera un dégradé allant de noir à gris moyen (100, 100, 100) \n",
"=> la couleur (2n, 0 , 0) donnera un dégradé allant de noir au rouge vif (200, 0, 0) \n",
"=> la couleur (0, 0, 3n%256) donnera un premier dégradé allant de noir au bleu vif (0, 0, 255), puis lorsque 3n dépasse 255 on reviend à zéro, jusqu'à atteindre la couleur (0, 0, 44) pour n=100. \n",
"\n",
"Pour commencer nous allons faire un \"mix\" de tout cela, soit par exemple : (4n%256, 2n, 6n%256). \n",
"Puis tester aussi la formule suivante: (255-log10(n)x127, 255-log10(n)x127, log10(n)x127). \n",
"Et pourquoi pas tester aussi une variante personnelle. \n",
"\n",
"**Écrire une fonction ```colorise```** permettant de fixer une couleur (d'après les formules ci-dessus) à chaque pixel d'un rectangle, en fonction d'une valeur de $n$, avec $-1<n<100$ : "
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"from PIL import Image\n",
"from math import log10, sqrt\n",
"\n",
"from random import randint\n",
"\n",
"def colorise(img, taille):\n",
" \"Colorise un carré de pixel, avec des bandes, selon les formules proposées ci-dessus :\"\n",
" \n",
" for x in range(400):\n",
" for y in range(400):\n",
" n = int(sqrt((x-200)**2 + (y-200)**2)) # essayer de faire un truc joli\n",
" if n == -1:\n",
" img.putpixel((x, y), (0,0,0))\n",
" else:\n",
" img.putpixel((x, y), (4*n%256, 2*n, 6*n%256))\n",
"\n",
" # Faire appel aux méthodes :\n",
" # putpixel(); save() et show()\n",
" # Voir : #https://info.blaisepascal.fr/pillow\n",
"\n",
"taille = 400\n",
"img = Image.new('RGB',(taille,taille),(255,255,255))\n",
"colorise(img, taille)\n",
"img.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h4 style = 'color: SeaGreen'> 74/ Association des fonctions précédentes :</h4>\n",
"\n",
"Associer les fonctions précédentes pour obtenir le tracé des fractales de Julia. \n",
"La fonction ```dessineFractale``` est une évolution de la fonction ```colorise``` qui gère le tracé (position et couleur de chaque pixel) de la fractale de Julia, à l'aide des fonctions : ```convert``` et ```ensembleJulia```. \n",
"Tester les fractales pour les valeurs du paramètre $c$ successivement égal à : \n",
"- $-0.5+0.6i$\n",
"- $-0.8-0.18i$\n",
"- $0-0.8i$\n",
"- $0.285+0.013i$\n"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [],
"source": [
"from PIL import Image\n",
"from math import log10\n",
"\n",
"#***Déclaration des constantes :***\n",
"taille = 1000\n",
"reMax = -0.5\n",
"reMin = 0.5\n",
"imgMax = -0.5\n",
"imgMin = 0.5\n",
"\n",
"#***Déclaration des fonction locales :***\n",
"def ensembleJulia (z: complex, c: complex) -> int :\n",
" '''Prend une suite de Julia et un point d'affixe z :\n",
" Retourne => -1 si le point est dans l'ensemble J(c): le module de tous les termes est < 2\n",
" Retourne l'indice i du premier terme ayant un module supérieur à 2\n",
" '''\n",
" u = z\n",
" for i in range (20):\n",
" u = u **2 + c\n",
" if abs(u) > 2:\n",
" return i\n",
" return -1\n",
"\n",
"def convert(x:int, y:int, taille:int) ->complex :\n",
" \"Convertit un point du plan (de l'image) de coordonnées x, y en un nombre complexe z = re + img*j\"\n",
" return complex(x*(reMax-imgMin)/taille - (reMax-reMin)/2, y*(imgMax-imgMin)/taille - (imgMax-imgMin)/2)\n",
"\n",
"def dessineFractale(img, taille, c):\n",
" \"Construit la fractale à partir d'une carré de pixels à colorer en fonction de la valeur de n :\"\n",
" for x in range(taille):\n",
" for y in range(taille):\n",
" n = ensembleJulia(convert(x, y, taille), c)\n",
" if n == -1:\n",
" img.putpixel((x, y), (0,0,0))\n",
" else:\n",
" img.putpixel((x, y), (4*n%256, 2*n, 6*n%256))\n",
"\n",
"#*** Programme principal :***\n",
"\"Tester les fractales pour le paramètre c = -0.5+0.6j; -0.8-0.18j; 0-0.8j; 0.285+0.013j \"\n",
"img = Image.new('RGB',(taille,taille),(255,255,255))\n",
"dessineFractale(img, taille, 0-0.8j)\n",
"img.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">8/ Mise en évidence de la structure de la fractale : </h3>\n",
"\n",
"Une figure fractale est un objet mathématique qui présente une structure similaire à toutes les échelles. \n",
"A partir d'une fractale de niveau 0, vérifier qu'il est possible d'obtenir une fractale de niveau 1, puis 2 et ainsi de suite : \n",
"=> Pour cela adapter les constantes du script (taille etc...) pour zoomer de plus en plus.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"color: DarkBlue\">9/ Ensemble de Mandelbrot : </h3>\n",
"\n",
"Prolongement possible aux ensembles de Julia : $\\Rightarrow$ les ensembles de Mandelbrot. \n",
"A voir :\n",
"- https://fr.wikipedia.org/wiki/Ensemble_de_Mandelbrot\n",
"- le logiciel Xaos."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.8.10 64-bit",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}