{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Exercices du livre - Chapitre 11 - solutions\n",
    "\n",
    "---\n",
    "\n",
    "<table class=\"appbclp1\">\n",
    "<tr> <td style=\"font-weight: bold!;\">auteurs :</td><td style=\"text-align: left!;\">Laurent Pointal &lt;<a href=\"mailtp:laurent.pointal@limsi.fr\">laurent.pointal@limsi.fr</a>&gt; &amp; Bob Cordeau &lt;<a href=\"pycours@kordeo.eu\">pycours@kordeo.eu</a>&gt; </td> </tr>\n",
    "<tr> <td style=\"font-weight: bold!;\">licence :</td><td style=\"text-align: left!;\">Creative Commons Attribution-ShareAlike 4.0 International Public License (CC BY-SA 4.0) </td> </tr>\n",
    "<tr> <td style=\"font-weight: bold!;\">source :</td><td style=\"text-align: left!;\"><a href=\"https://github.com/lpointal/appbclp\">https://github.com/lpointal/appbclp</a></td> </tr>\n",
    "<tr> <td style=\"font-weight: bold!;\">description :</td><td style=\"text-align: left!;\">Les programmes dans ce Notebook Jupyter servent de support au livre <span style=\"font-style: italic!;\">« Python 3 - Apprendre à  programmer dans l'écosystème Python»</span>, édition Dunod, dans lequel les différentes sections sont expliquées </td> </tr>\n",
    "<tr> <td style=\"font-weight: bold!;\">url :</td><td style=\"text-align: left!;\"><a href=\"https://www.dunod.com/sciences-techniques/python-3\">https://www.dunod.com/EAN/9782100809141</a></td> </tr>\n",
    "</table>\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercice 1\n",
    "\n",
    "# Définition de fonction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
    "def listAleaInt(n, a, b):\n",
    "    \"\"\"Retourne une liste de <n> entiers aléatoires entre <a> et <b>.\"\"\"\n",
    "    return [randint(a, b) for i in range(n)]\n",
    "\n",
    "# Programme principal =========================================================\n",
    "n = int(input(\"Entrez un entier [2 .. 100] : \"))\n",
    "while not(n >= 2 and n <= 100):\n",
    "    n = int(input(\"Entrez un entier [2 .. 100], s.v.p. : \"))\n",
    "\n",
    "# Construction de la liste\n",
    "seed()  # initialise le générateur de nombres aléatoires\n",
    "t = listAleaInt(n, 0, 500)\n",
    "\n",
    "# Sont-ils différents ?\n",
    "tousDiff = True\n",
    "i = 0\n",
    "while tousDiff and i < (n-1):\n",
    "    j = i + 1\n",
    "    while tousDiff and j < n:\n",
    "        if t[i] == t[j]:\n",
    "            tousDiff = False\n",
    "        else:\n",
    "            j += 1\n",
    "    i += 1\n",
    "\n",
    "if tousDiff:\n",
    "    print(\"\\nTous les éléments sont distincts.\")\n",
    "else:\n",
    "    print(\"\\nAu moins une valeur est répétée.\")\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercice 2\n",
    "\n",
    "# Import ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
    "from random import seed, randint\n",
    "\n",
    "# Définition de fonction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
    "def listAleaInt(n, a, b):\n",
    "    \"\"\"Retourne une liste de <n> entiers aléatoires entre <a> et <b>.\"\"\"\n",
    "    return [randint(a, b) for i in range(n)]\n",
    "\n",
    "# Programme principal =========================================================\n",
    "n = int(input(\"Entrez un entier [1 .. 100] : \"))\n",
    "while not(n >= 1 and n <= 100):\n",
    "    n = int(input(\"Entrez un entier [1 .. 100], s.v.p. : \"))\n",
    "\n",
    "seed()  # initialise le générateur de nombres aléatoires\n",
    "avant = listAleaInt(n, 0, 500)\n",
    "apres = list(set(avant))\n",
    "\n",
    "if len(avant) == len(apres):\n",
    "    print(\"\\nTous les éléments sont distincts.\")\n",
    "else:\n",
    "    print(\"\\nAu moins une valeur est répétée.\")\n",
    "print(avant)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercice 3\n",
    "\n",
    "from time import time\n",
    "import numpy as np\n",
    "\n",
    "L = list(range(1_000))\n",
    "a = np.array(L)\n",
    "\n",
    "t0 = time()\n",
    "L2 = [x**2 for x in L]\n",
    "d1 = time() - t0\n",
    "\n",
    "t0 = time()\n",
    "a = a**2\n",
    "d2 = time() - t0\n",
    "\n",
    "print(f\"Carrée de la liste : {1e6 * d1:.1f} ns\")\n",
    "print(f\"carrée du ndarray : {1e6 * d2:.1f} ns\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercice 4\n",
    "\n",
    "import math\n",
    "def noncarres(n):\n",
    "    lst = []\n",
    "    i = 1\n",
    "    while i <= n :\n",
    "        reste = math.sqrt(i) - int(math.sqrt(i))\n",
    "        if reste != 0:          # condition était inversée\n",
    "            lst.append(i)\n",
    "        i = i + 1               # incrémentation était hors de la boucle\n",
    "     return lst                 # print était utilisé \n",
    "\n",
    "\"\"\"\n",
    "Trois bugs à corriger :\n",
    "  * la condition du if est inversée → if reste!= 0 ;\n",
    "  * l'incrémentation du i doit être faite systématiquement, dans le corps du while, sinon on a une \n",
    "    boucle ∞ → désindenter le i=i+1 pour qu'il soit au même niveau que le if ;\n",
    "  * la fonction doit retourner la liste, pas l'afficher → dernière ligne return lst.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercice 5\n",
    "\n",
    "# Import ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Programme principal ==========================================================\n",
    "X = np.arange(-6, 8 , 0.5)\n",
    "Y1 = (2 * X**3) - (5 * X)\n",
    "Y2 = (6 * X**2) - 5\n",
    "Y3 = 12 * X\n",
    "\n",
    "# Représentation graphique\n",
    "plt.title(\"Graphes de fonctions\")\n",
    "plt.plot(X, Y1, label='cubique')\n",
    "plt.plot(X, Y2, label='dérivée première')\n",
    "plt.plot(X, Y3, label='dérivée seconde')\n",
    "plt.xlabel(\"x\")\n",
    "plt.ylabel(\"y\")\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercice 6\n",
    "\n",
    "# Import ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
    "from random import random\n",
    "from collections import namedtuple\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Définition de fonction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
    "def coeff_dir(nuage):\n",
    "    \"\"\"\n",
    "        Retourne m le coefficient directeur d'un nuage de points\n",
    "        selon la méthode des moindres carrés.\n",
    "    \"\"\"\n",
    "    n = len(nuage)\n",
    "\n",
    "    # On décompose la formule donnée sous la forme plus simple :\n",
    "    # m = (a - b1*b2) / (c - (b1**2 / n))\n",
    "    a, b1, b2, c = 0.0, 0.0, 0.0, 0.0\n",
    "    for p in nuage:\n",
    "        a += p.x * p.y\n",
    "        b1 += p.x\n",
    "        b2 += p.y\n",
    "        c += (p.x ** 2)\n",
    "\n",
    "    return (a - (b1 * b2) / n) / (c - (b1**2 / n))\n",
    "\n",
    "\n",
    "def coeff_cst(nuage, m):\n",
    "    \"\"\"\n",
    "        Retourne b le coefficient constant d'un nuage de points\n",
    "        de coefficient directeur m.\n",
    "    \"\"\"\n",
    "\n",
    "    # b est donné par : b = y_m - m*x_m\n",
    "    # où x_m et y_m sont les valeurs moyennes des abscisses et des ordonnées\n",
    "    x_m, y_m = 0.0, 0.0\n",
    "    for p in nuage:\n",
    "        x_m += p.x\n",
    "        y_m += p.y\n",
    "\n",
    "    n = len(nuage)\n",
    "    x_m /= n\n",
    "    y_m /= n\n",
    "\n",
    "    return y_m - m * x_m\n",
    "\n",
    "\n",
    "# Programme principal ==========================================================\n",
    "Point = namedtuple('Point', ['x', 'y'])  # définition du type Point\n",
    "nuage = []                               # initialisation du nuage de points\n",
    "\n",
    "for i in range(1, 101):\n",
    "    p = Point(100*random() + i, 15*random() + i)\n",
    "    nuage.append(p)\n",
    "\n",
    "m = coeff_dir(nuage)\n",
    "b = coeff_cst(nuage, m)\n",
    "print(f\"\\nDroite des moindres carrés : y = {m:.2g}x \", end=\"\")\n",
    "print(f\"+ {b:.2g}\") if b >= 0 else print(f\"- {-b:.2g}\")\n",
    "\n",
    "# Représentation graphique\n",
    "X = [p.x for p in nuage]\n",
    "Y = [p.y for p in nuage]\n",
    "plt.scatter(X, Y, label='nuage de points')\n",
    "plt.plot(X, [m*x + b for x in X], 'g-', label='droite des moindres carrés')\n",
    "plt.xlabel(\"x\")\n",
    "plt.ylabel(\"y\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
