{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "FEUILLE DE TP 12\n",
    "\n",
    "# Méthode de Newton"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La méthode de Newton nous permet de calculer numériquement les zéros d'une fonction $f:[a,b]\\rightarrow \\mathbb{R}$, c'est-à-dire les solutions de l'équation $f(x) = 0$.\n",
    "\n",
    "Supposons $f$ de classe $C^1$ et $x_0 \\in (a,b)$ un point arbitraire. \n",
    "\n",
    "L'équation de la tangente au graphe de la fonction $f$ au point d'absisse $x_0$ est donnée par\n",
    "\n",
    "\\begin{equation}\n",
    "y = f(x_0) + f'(x_0)(x-x_0)\\,.\n",
    "\\end{equation}\n",
    "\n",
    "Pour obtenir une approximation de la solution, on pose $y = 0$ et si $f'(x_0) \\neq 0$ on obtient\n",
    "\n",
    "\\begin{equation}\n",
    "x_1 = x_0 - \\frac{f(x_0)}{f'(x_0)}\\,.\n",
    "\\end{equation}\n",
    "\n",
    "On peut alors répéter le même raisonnement en considérant $x_1$ au lieu de $x_0$ pour calculer l'approximation de \n",
    "$x_2$ et ainsi de suite. \n",
    "\n",
    "\n",
    "La méthode de Newton consiste donc à construire une suite d'approximations $x_k$ de la solution $x^*$ de l'équation $f(x) = 0$, définie par\n",
    "\n",
    "\\begin{equation}\n",
    "x_{k+1} = x_k - \\frac{f(x_k)}{f'(x_k)}\\,, \\qquad k\\in \\mathbb{N}\\, . \\qquad (1)\n",
    "\\end{equation}\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Calcul de valeurs approchées de nombres irrationnels \n",
    "\n",
    "Nous allons utiliser la méthode de Newton pour calculer des approximations de quelques nombres irrationnels. On considère\n",
    "\n",
    "\\begin{equation}\n",
    "f_0(x) = x^3-2~ \\text{ avec } ~ x\\in [1,4] \\, , \\quad f_1(x) = \\sin^2(x)~  \\text{ avec } ~ x\\in [2,4] \n",
    "\\end{equation}\n",
    "\n",
    "En appliquant la méthode de Newton à $f_0$ et $f_1$, on espère obtenir respectivement une approximation de $2^{1/3}$ et $\\pi$. \n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 1\n",
    "\n",
    "Définissez les fonctions $f_0$ et $f_1$, ainsi que leurs dérivés $f'_0$ et $f'_1$, et tracez-les sur leur intervalle de définition.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#DEFINIR LES FONCTIONS\n",
    "\n",
    "def f0(x): \n",
    "    return np.power(x, 3) - 2\n",
    "\n",
    "def f0prime(x): \n",
    "    return 3 * np.power(x, 2)\n",
    "\n",
    "def f1(x): \n",
    "    return np.power(np.sin(x), 2)\n",
    "    \n",
    "def f1prime(x): \n",
    "    return 2 * np.cos(x) * np.sin(x)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Fonction f1 et sa dérivée')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 69352 characters]\n",
      "text/plain": [
       "<Figure size 1200x1200 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "## COMPLETEZ ....\n",
    "## METTRE LES GRAPHIQUES \n",
    "x0 = np.linspace(1, 4, 200)\n",
    "\n",
    "# Graphique\n",
    "fig = plt.figure(figsize=(12, 12))\n",
    "ax = fig.add_subplot(2, 2, 1)\n",
    "ax.plot(x0, f0(x0), label=f'$f$')\n",
    "ax.plot(x0, f0prime(x0), label=f\"$f'$\")\n",
    "ax.legend()\n",
    "ax.set_xlabel(f'$x$')\n",
    "ax.set_ylabel(f'$f(x)$')\n",
    "ax.set_title('Fonction f0 et sa dérivée')\n",
    "\n",
    "x1 = np.linspace(2, 4, 200)\n",
    "ax = fig.add_subplot(2, 2, 2)\n",
    "ax.plot(x1, f1(x1), label=f'$f$')\n",
    "ax.plot(x1, f1prime(x1), label=f\"$f'$\")\n",
    "ax.legend()\n",
    "ax.set_xlabel(f'$x$')\n",
    "ax.set_ylabel(f'$f(x)$')\n",
    "ax.set_title('Fonction f1 et sa dérivée')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Question 2\n",
    "\n",
    "Avant d'implémenter la méthode de Newton (1) on a besoin de choisir un __critère d’arrêt__: à chaque itération $k$ de la méthode ce critère nous permet de décider s'il faut caluler l'approximation suivante ou arrêter l'algorithme. \n",
    "\n",
    "On choisira d’implémenter ici un critère d’arrêt donné par:\n",
    "\n",
    "\\begin{equation}\n",
    "|f(x_k)|< \\epsilon  \\quad \\text{ OU } \\quad   k> N_{max}\n",
    "\\end{equation}\n",
    "\n",
    "où $\\epsilon>0$ est un réel fixé et $N_{max} \\in \\mathbb{N}$ est le nombre maximal d'itérations.\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "Écrire une fonction __newton__ prenant en argument:\n",
    "\n",
    "- une fonction __fun__ \n",
    "- sa dérivée __funprime__ \n",
    "- une condition initiale $x_0$\n",
    "- une tolérance $\\epsilon>0$ pour le critère d’arrêt\n",
    "- un nombre d'itération maximal $N_{max}$ pour le critère d’arrêt\n",
    "\n",
    "\n",
    "et qui donne en sortie \n",
    "\n",
    "- le nombre d'itérations nécéssaires pour vérifier le critère d'arrêt,\n",
    "- la solution approchée $x^*$ calculée avec la méthode de Newton.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def newton(fun, funprime, x0, epsilon,Nmax):\n",
    "    \"\"\"\n",
    "    Algorithme de Newton pour résoudre f(x) = 0 \n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    - fun: fonction(x) \n",
    "        fonction f\n",
    "    - funprime: fonction(x)\n",
    "        dérivé de f\n",
    "    - x0: float \n",
    "        approximation initiale  \n",
    "    - epsilon: float\n",
    "        tolerance dans le critere d'arret\n",
    "    - Nmax: int\n",
    "        nombre d'iterations maximal\n",
    "\n",
    "    Renvoie\n",
    "    ----------\n",
    "    - k: float\n",
    "        nombre d'iteration\n",
    "    - xstar: float\n",
    "        solution approchée\n",
    "    \"\"\"\n",
    "    k = 0\n",
    "    xk = x0\n",
    "    while np.abs(fun(xk)) > epsilon and k < Nmax:\n",
    "        k += 1\n",
    "        xk -= fun(xk)/funprime(xk)\n",
    "    return k, xk"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 2 \n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Choisir un point $x_0$ arbitraire dans l'intervalle de définition des deux fonctions ci-dessus, calculer les solutions approchées $\\tilde{x}_0$ et $\\tilde{x}_1$ des équations $f_0(x) = 0$ et $f_1(x)=0$ en utilisant la méthode de Newton avec $\\epsilon = 10^{-14}$ et $N_{max} = 1,2,\\ldots,20$. \n",
    "\n",
    "Tracez le logarithme des erreurs $|\\tilde{x}_0 - 2^{1/3}|$ et $|\\tilde{x}_1 - \\pi| $ en fonction de $N_{max}$.  \n",
    "\n",
    "Qu'est-ce que vous observez ? Pourquoi les deux courbes sont-elles si différentes ?\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Erreurs des valeurs x0 et x1')"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 35000 characters]\n",
      "text/plain": [
       "<Figure size 1200x1200 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x0_sol = [[], []]\n",
    "x1_sol = [[], []]\n",
    "\n",
    "for n in range(1, 21):\n",
    "    x0 = 1.1\n",
    "    x1 = 2.3\n",
    "    epsilon = 10e-14\n",
    "    sol_f0 = newton(f0, f0prime, x0, epsilon, n)\n",
    "    sol_f1 = newton(f1, f1prime, x1, epsilon, n)\n",
    "    x0_sol[0].append(sol_f0[0])\n",
    "    x0_sol[1].append(sol_f0[1])\n",
    "    x1_sol[0].append(sol_f1[0])\n",
    "    x1_sol[1].append(sol_f1[1])\n",
    "    \n",
    "xx0 = np.linspace(1, 4, 200)\n",
    "xx1 = np.linspace(2, 3, 200)\n",
    "\n",
    "# Graphique\n",
    "fig = plt.figure(figsize=(12, 12))\n",
    "ax = fig.add_subplot(2, 2, 1)\n",
    "ax.plot(x0_sol[0], np.abs(x0_sol[1] - np.power(2, 1/3)), label=f'Erreur x0')\n",
    "ax.plot(x1_sol[0], np.abs(np.array(x1_sol[1]) - np.pi), label=f'Erreur x1')\n",
    "ax.legend()\n",
    "#ax.set_xscale('log')\n",
    "ax.set_yscale('log')\n",
    "ax.set_xlabel('$N_{max}$')\n",
    "ax.set_ylabel('Erreur')\n",
    "ax.set_title('Erreurs des valeurs x0 et x1')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Un exemple avec plusieurs solutions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Si on applique la méthode de Newton à une fonction $f$ telle que $f(x) = 0$ a plusieurs solutions, on peut s'attendre à deux résultats possibles: soit la méthode ne converge pas, soit elle converge vers un seul des zéros de $f$. En particulier la méthode peut converger vers des zéros différents si on choisit de points initiaux $x_0$ différents.\n",
    "\n",
    "L'ensemble des $x_0$ tels que la méthode converge vers la solution $x^*$ s'appelle le __bassin d'attraction__ de $x^*$. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 3\n",
    "\n",
    "Soit $f$ la fonction telle que $f(x) =x^3 - 4 x+ 1$. Combien l’équation $f(x) = 0$ admet-elle de solutions ?\n",
    "\n",
    "Rechercher ces solutions avec la fonction __newton__ en initialisant successivement la méthode avec différentes valeurs initiales $x_0$. \n",
    "\n",
    "Tracer la fonction $f(x)$ et vérifier le résultat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    \"\"\" definition de f \"\"\"\n",
    "    return np.power(x, 3) - 4 * x + 1\n",
    "\n",
    "def fprime(x): \n",
    "    \"\"\" definition de f' \"\"\"\n",
    "    return 3 * np.power(x, 2) - 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Solution pour x_start=-2.5\n",
      "x_sol = -2.1864406779661016 pour 1 itérations\n",
      "x_sol = -2.118117687826545 pour 2 itérations\n",
      "x_sol = -2.114914460488018 pour 3 itérations\n",
      "x_sol = -2.114907541509005 pour 4 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "x_sol = -2.114907541476756 pour 5 itérations\n",
      "\n",
      "Solution pour x_start=0\n",
      "x_sol = 0.25 pour 1 itérations\n",
      "x_sol = 0.2540983606557377 pour 2 itérations\n",
      "x_sol = 0.25410168836283464 pour 3 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "x_sol = 0.2541016883650524 pour 4 itérations\n",
      "\n",
      "Solution pour x_start=2.5\n",
      "x_sol = 2.0508474576271185 pour 1 itérations\n",
      "x_sol = 1.885793368253518 pour 2 itérations\n",
      "x_sol = 1.8613332057733178 pour 3 itérations\n",
      "x_sol = 1.8608060959714212 pour 4 itérations\n",
      "x_sol = 1.8608058531117548 pour 5 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "x_sol = 1.8608058531117033 pour 6 itérations\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Fonction f et sa dérivée')"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 38856 characters]\n",
      "text/plain": [
       "<Figure size 1200x1200 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "## VOTRE REPONSE ICI\n",
    "# ON PEUT PRENDRE EN LE JUSTIFIANT : x0 = -2.5,   x0 = 0, x0 = 2.5\n",
    "# NE PRENEZ PAS NMax TROP GRAND  (on pourra aussi justifier cela )\n",
    "for x_start in [-2.5, 0, 2.5]:\n",
    "    print(f\"Solution pour x_start={x_start}\")\n",
    "    for n in range(1, 21):\n",
    "        x_sol = newton(f, fprime, x_start, epsilon, n)\n",
    "        print(f\"x_sol = {x_sol[1]} pour {x_sol[0]} itérations\")\n",
    "    print(\"\")\n",
    "\n",
    "xx = np.linspace(-3, 3, 200)\n",
    "\n",
    "# Graphique\n",
    "fig = plt.figure(figsize=(12, 12))\n",
    "ax = fig.add_subplot(2, 2, 1)\n",
    "ax.plot(xx, f(xx), label=f'$f$')\n",
    "ax.plot(xx, fprime(xx), label=f\"$f'$\")\n",
    "ax.plot(xx, np.zeros(xx.size))\n",
    "ax.legend()\n",
    "ax.set_xlabel(f'$x$')\n",
    "ax.set_ylabel(f'$f(x)$')\n",
    "ax.set_title('Fonction f et sa dérivée')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Manipulation d'images en Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On commence par importer le module matplotlib.image, puis on importe l’image image0.png et on l’affiche \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f4c55de14b0>"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 405364 characters]\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.image as mpimg\n",
    "\n",
    "# DECOMMENTEZ  \n",
    "img0 = mpimg.imread('image0.png')\n",
    "plt.imshow(img0)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 4\n",
    "\n",
    "Quel objet python est img0? (Utiliser la fonction __type__)\n",
    "\n",
    "Recommencer avec le fichier image1.png\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f4c55c5e710>"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 492140 characters]\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "## VOTRE CODE ICI\n",
    "print(type(img0))\n",
    "\n",
    "img1 = mpimg.imread('image1.png')\n",
    "plt.imshow(img1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 5\n",
    "\n",
    "Les objet img0 et img1 sont des *numpy arrays* de taille $(N_x,N_y,3)$ où $N_x$ est le nombre de pixels (de points) dans la diréction horizontale et $N_y$ est le nombre de pixels dans la diréction verticale.\n",
    "\n",
    "La couleur de chaque pixel est codée par un vecteur [R, G, B] de taille 3 dit RGB (ou RVB en français\n",
    "rouge-vert-bleu). Chaque coordonnée varie entre 0 et 1 (ou 0 et 255 selon la convention). [1, 0, 0] code\n",
    "le rouge, [0, 1, 0] le vert, [0, 0, 1] le bleu, [1, 1, 1] le blanc et [0, 0, 0] le noir. Par exemple:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "La couleur du pixel de img0 de coordonnées (1,100) est donnée par [R G B]= [0.9372549 0.9372549 0.9372549 1.       ]\n",
      "La couleur du pixel de img1 de coordonnées (50,100) est donnée par [R G B]= [0.  0.4 1.  1. ]\n"
     ]
    }
   ],
   "source": [
    "print('La couleur du pixel de img0 de coordonnées (1,100) est donnée par [R G B]=', img0[1,100,:])\n",
    "print('La couleur du pixel de img1 de coordonnées (50,100) est donnée par [R G B]=', img1[50,100,:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Créer une image de taille $N \\times N$ pixels entièrement noire, puis blanche, puis rouge. Créer une autre image de taille $N \\times N$ dont la moitié droite est rouge et la moitié gauche est bleue."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f4c559baf50>"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 7636 characters]\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "## VOTRE CODE ICI \n",
    "N = 50\n",
    "imageBlack = np.zeros((N, N, 3))\n",
    "plt.imshow(imageBlack)\n",
    "\n",
    "imageWhite = np.ones((N, N, 3))\n",
    "plt.imshow(imageWhite)\n",
    "\n",
    "imageRed = np.ones((N, N, 3))\n",
    "imageRed[::] = [1, 0, 0]\n",
    "plt.imshow(imageRed)\n",
    "\n",
    "imageDB = np.zeros((N, N, 3))\n",
    "imageDB[]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fractale de Newton\n",
    "\n",
    "\n",
    "On considère la fonction holomorphe $f:\\mathbb{C} \\rightarrow \\mathbb{C}$ telle que\n",
    "\n",
    "\\begin{equation}\n",
    "f(z) = z^3-1\n",
    "\\end{equation}\n",
    "\n",
    "L'équation $f(z)= 0$ admets trois racines dinstinctes: \n",
    "\n",
    "\\begin{equation}\n",
    " {r}_0 =  -\\frac{1}{2}+ \\frac{\\sqrt{3}}{2} i,\\quad {r}_1 =  -\\frac{1}{2}- \\frac{\\sqrt{3}}{2} i\\,,\\quad r_2 = 1 \\,.\n",
    "\\end{equation}\n",
    "\n",
    "La méthode de Newton peut etre appliquée sans modifications aussi dans ce cas. \n",
    "\n",
    "Ici nous voulons étudier les __bassins d'attractions__ des différentes racines de $f$. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 6\n",
    "\n",
    "Afin de définir le nombre complexe $z = x + i y$ en Python, on définit z = complex(x, y) par exemple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Soit z =(4+3j), alors z^2 =(7+24j)\n"
     ]
    }
   ],
   "source": [
    "z = complex(4,3)\n",
    "print('Soit z ={}, alors z^2 ={}'.format(z,z**2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Définir la fonction $f(z) = z^3-1$ ainsi que sa dérivée $f'$ et un np.array appelé __roots__ de taille 3 contenant les trois racines distinctes de f "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def f(z): \n",
    "    \"\"\"definir f  \"\"\"\n",
    "    return np.power(z, 3) - 1\n",
    "\n",
    "def fprime(z): \n",
    "    \"\"\" definir f' \"\"\"\n",
    "    return 3 * np.power(z, 2)\n",
    "    \n",
    "roots = np.array([complex(-1/2, np.sqrt(3)/2), complex(-1/2, - np.sqrt(3)/2), complex(1, 0)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Question 7\n",
    "\n",
    "Implémenter une méthode de Newton modifiée __newtonMod__ à partir de la fonction __newton__ implémentée\n",
    "dans la Question 2. On demande les modifications suivantes : on va utiliser le fait qu’on a une expression\n",
    "algébrique des racines de f afin d’étudier plus simplement la dépendance de la méthode de Newton\n",
    "en fonction de la condition initiale et on remplace le critère d’arrêt de la Question 2 par le critère d’arrêt:\n",
    "\n",
    "\\begin{equation}\n",
    "|x_k − r_0| < \\epsilon \\quad \\text{ OR }\\quad |x_k − r_1| < \\epsilon\\quad\\text{ OR }\\quad |x_k − r_2| < \\epsilon  \\quad\\text{ OR }\\quad k > N_{max}\n",
    "\\end{equation}\n",
    "\n",
    "\n",
    "La fonction __newtonMod__ doit avoir en sortie un argument additionnel par rapport à  la fonction __newton__:\n",
    "\n",
    "- un entier $b$ pouvant prendre 4 valeurs: $b=-1$ si la la méthode n’a pas convergé (c'est-à-dire si on depasse le nombre d'iterations maximal), ou $b=j$ si la méthode a convergé vers la racine $r_j$  avec $j=0,1,2$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def newtonMod(fun, funprime, x0, roots, epsilon,Nmax):\n",
    "    \"\"\"\n",
    "    Algorithme de Newton pour résoudre f(x) = 0 \n",
    "    avec des valeurs cibles de la racine fournies par le tableau roots (de taille 3): \n",
    "    Si la racine obenue coincide avec roots[i] on retournera l'indice i (voir le paramètre de sortie b ci-dessous).\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    - fun: fonction(x) \n",
    "        fonction f\n",
    "    - funprime: fonction(x)\n",
    "        dérivé de f\n",
    "    - x0: float \n",
    "        approximation initiale\n",
    "    - roots:\n",
    "        tableau (de talle 3) des valeurs cibles de racine \n",
    "    - epsilon: float\n",
    "        tolerance dans le critere d'arret\n",
    "    - Nmax: int\n",
    "        nombre d'iterations maximal\n",
    "\n",
    "    Renvoie\n",
    "    ----------\n",
    "    - b : int\n",
    "        indicateur de la racine\n",
    "    - k: float\n",
    "        nombre d'iteration\n",
    "    - xstar: float\n",
    "        solution approchée\n",
    "    \"\"\"\n",
    "    xk = x0\n",
    "    k = 0\n",
    "    r0, r1, r2 = roots[0], roots[1], roots[2]\n",
    "    while np.abs(xk - r0) > epsilon and np.abs(xk - r1) > epsilon and np.abs(xk - r2) > epsilon and k < Nmax:\n",
    "        k += 1\n",
    "        xk -= fun(xk)/funprime(xk)\n",
    "    if k > Nmax:\n",
    "        b = -1\n",
    "    else:\n",
    "        b = np.abs(roots - xk).argmin()\n",
    "    return b, k, xk"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 8\n",
    "\n",
    "\n",
    "Définir un vecteur $p$ de taille $N$, obtenus en divisant l'interval $[-1,1]$ en $N-1$ sous-intervalles égaux.\n",
    "\n",
    "Définir une images noire de taille $N \\times N$ comme dans l'exercice 5 et l'appeler __image0__ .\n",
    "\n",
    "Chaque pixel d' __image0__ corresponde à un point dans le carré $[-1,1]\\times [-1,1]$. \n",
    "Pour chaque pixel corréspondant aux indices $(i_x,i_y)$, appellez la méthode __newtonMod__ en prenant pour condition initiale le nombre complexe \n",
    "\n",
    "\\begin{equation}\n",
    "z_0 = a+ i\\, b \\,, \\quad \\text{ où } \\quad a= p[i_x] \\, \\text{ et }\\, b= p[i_y] \n",
    "\\end{equation}\n",
    "\n",
    "\n",
    "et colorier le pixel $(i_x,i_y)$ de __image0__ en noir si la méthode n’a pas convergé et sinon en rouge, vert ou bleu selon la racine vers\n",
    "laquelle elle a convergé. \n",
    "\n",
    "\n",
    "\n",
    "Essayer avec N = 50 puis N = 500.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f4c55b3d9c0>"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 37484 characters]\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# VOTRE CODE ICI\n",
    "N = 500\n",
    "p = np.linspace(-1, 1, N)\n",
    "image0 = np.zeros((N, N, 3))\n",
    "for i in range(N):\n",
    "    for j in range(N):\n",
    "        z0 = complex(p[i], p[j])\n",
    "        b, k, x = newtonMod(f, fprime, z0, roots, 10e-14, 5)\n",
    "        if b == -1:\n",
    "            image0[i, j] = [0, 0, 0]\n",
    "        elif b == 0:\n",
    "            image0[i, j] = [1, 0, 0]\n",
    "        elif b == 1:\n",
    "            image0[i, j] = [0, 1, 0]\n",
    "        elif b == 2:\n",
    "            image0[i, j] = [0, 0, 1]\n",
    "            \n",
    "plt.imshow(image0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 9\n",
    "\n",
    "Sur une nouvelle image, colorier de manière similaire chaque pixel sur une échelle de gris proportionnellement\n",
    "au nombre d’itérations $k$ nécessaires à la convergence de la méthode, $k/N_{max} \\in [0, 1]$; c'est-à-dire en saisissant le code [R G B] donné par $[k/N_{max},k/N_{max},k/N_{max}]$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f4c55ccabc0>"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 65272 characters]\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# VOTRE CODE ICI \n",
    "N = 500\n",
    "Nmax = 10\n",
    "p = np.linspace(-1, 1, N)\n",
    "image0 = np.zeros((N, N, 3))\n",
    "for i in range(N):\n",
    "    for j in range(N):\n",
    "        z0 = complex(p[i], p[j])\n",
    "        b, k, x = newtonMod(f, fprime, z0, roots, 10e-14, Nmax)\n",
    "        image0[i, j] = [k/Nmax, k/Nmax, k/Nmax]\n",
    "            \n",
    "plt.imshow(image0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Question 10\n",
    "\n",
    "Commentez les  observations\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
