{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"float: left;\">\n",
    "Université Toulouse 3,\n",
    "<br>\n",
    "Licence\n",
    "</div>\n",
    "<div style=\"float: right;\">\n",
    "Méthodes numériques : LU, systèmes, EDO,<br>\n",
    "2023-2023\n",
    "</div>\n",
    "<br>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div align=\"center\"; style=\"font-size: 200%; font-weight: bold;\">\n",
    "TP 1 - Prise en main de Python et Jupyter\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. Introduction\n",
    "\n",
    "Le but de ce TP est de découvrir (re-découvrir) les bases de Python (pour ceux qui ne les connaissent pas ou les ont oubliées) et surtout les principales bibliothèques Python que nous serons amenés à utiliser pendant l'année. Il s'agit de : \n",
    "\n",
    "1. numpy : pour la manipulation de complexes et des tableaux (pour les matrices) \n",
    "2. numpy.linalg : pour effectuer des opérations d'algèbre linéaire. \n",
    "3. matplotlib.pylab : pour les représentations graphiques\n",
    "\n",
    "La suite de l'introduction décrit le fonctionnement de Jupyter, et rappelle les syntaxes de base en Python. Vous êtes autorisés à passer rapidement la fin de l'introduction si vous vous sentez à l'aise.\n",
    "\n",
    "Dans la deuxième partie, nous nous présentons ces bibliothèques (vous les avez peut-être déjà utilisées en L1 et/ou L2), et les fonctions principales dont nous aurons besoin dans les prochains TP. \n",
    "Dans la dernière partie vous trouverez quelques exercices concernant le cours de cette année. \n",
    "\n",
    "\n",
    "Vous pouvez vous envoyer par mails vos fichiers `.ipynb` à la fin de chaque séance, afin de garder une trace de votre travail.\n",
    "\n",
    "\n",
    "## 1.1 Fonctionnement de Jupyter\n",
    "\n",
    "Un fichier Jupyter (aussi appelé Notebook), est une succession de cellules. Chacune peut être modifiée par un double-clique, puis compilée avec le raccourci **ctrl + entrée**. Les raccourcis en haut de la page vous permettent de créer une nouvelle cellule, couper, copier, coller une cellule. Vous pouvez aussi changer le type d'une cellule : `Code` si vous voulez taper du code python (voir la cellule ci-dessous), `Markdown` pour créer une cellule de texte (comme celle que vous êtes en train de lire), ou `Raw` pour une cellule brute."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Une cellule de code, qu'on peut compiler avec Python. La ligne suivante permet d'importer \n",
    "# des modules dont on aura besoin par la suite. Prenez l'habitude de la placer dans la première \n",
    "# cellule de chacun de vos TP.\n",
    "\n",
    "%pylab inline\n",
    "\n",
    "def f(x):\n",
    "    return x+1\n",
    "\n",
    "y = 2\n",
    "print(\"y =\",y)\n",
    "print(\"f(y) =\",f(y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Attention, si vous compilez une cellule dans laquelle des variabiles sont nommées, Jupyter les gardera en mémoire lors de l'éxecution d'autres cellules. Ainsi, les variables `y` et `f` sont définis pour la suite du TP.\n",
    "\n",
    "\n",
    "## 1.2 Opérateurs usuels\n",
    "\n",
    "On rappelle dans ce tableau les opérateurs mathématiques classiques sous Python. Rappelons que Python est un langage typé.\n",
    "\n",
    "| Opérateur | Opération |\n",
    "|-|-|\n",
    "| `=` | Affectation de variable. On peut affecter plusieurs variables en une fois, en regroupant variables et valeurs à affecter dans des conteneurs. Par exemple: `a,b=1,2` ou encore `[x,y]=(0,0)` |\n",
    "| `+` | Addition, concaténation entre itérables de même type |\n",
    "| `*` | Multiplication, répétition d'un itérable |\n",
    "| `-` | Négation, opposé ou soustraction pour les valeurs numériques. Différence pour les ensembles |\n",
    "| `/` | Division |\n",
    "| `//` | Division entière |\n",
    "| `**` | Exposant |\n",
    "| `%` | Modulo |\n",
    "| `not` `or` `and` | Opérations booléennes |\n",
    "| `<` `<=` `==` `!=` `<>` `>=` `>` | Comparaison $<$ $\\leq$ $=$ $\\neq$ $\\neq$ $\\geq$ $>$ |\n",
    "| `in` | Présence d'une valeur dans un conteneur |\n",
    "| `not in` | Absence d'une valeur dans un conteneur |\n",
    "| `is` | Tester si une valeur est d'un type donné |\n",
    "| $\\vert$ `&` `^` | Opérations bits à bits sur les valeurs numériques. Union, intersection ou différence symétrique pour les ensembles |\n",
    "\n",
    "Python propose aussi des opérateurs combinés avec une affectation, dits *in situ*. En voici quelques-uns.\n",
    "\n",
    "| Opérateur | Opération |\n",
    "|-|-|\n",
    "| `x += y` | `x = x + y` |\n",
    "| `x *= y` | `x = x * y` |\n",
    "| `x -= y` | `x = x - y` |\n",
    "| `x /= y` | `x = x / y` |\n",
    "| `x //= y` | `x = x // y` |\n",
    "| `x **= y` | `x = x ** y` |\n",
    "| `x %= y` | `x = x % y` |\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.3 Fonctions\n",
    "\n",
    "### 1.3.a Définition de fonctions\n",
    "\n",
    "On crée une fonction avec la syntaxe suivante.\n",
    "\n",
    "```python\n",
    "def f(x):\n",
    "    # instructions\n",
    "    return valeur\n",
    "```\n",
    "\n",
    "On peut donner plusieurs variables en argument, et spécifier une valeur par défaut. Une variable avec une valeur par défaut devient optionnelle. De même, on peut donner plusieurs variables en sortie."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x, y=4, z=-1):\n",
    "    t1 = x + y + z\n",
    "    t2 = x * y * z\n",
    "    return t1, t2\n",
    "\n",
    "print(f(2, y = 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cette instruction stocke dans la variable `f` une fonction à trois variables `x`, `y` et `z`, qui renvoie deux éléments.\n",
    "Les variables `y` et `z` ont des valeurs par défaut. Le tableau suivant regroupe différentes manières d'appeler `f` ainsi que les valeurs prises par les paramètres `x`, `y` et `z`. \n",
    "\n",
    "| Appel | x | y | z |\n",
    "|-|-|-|-|\n",
    "| `t1, t2 = f(1, 2, 3)` | 1 | 2 | 3 |\n",
    "| `t1, t2 = f(x=1, y=2, z=3)` | 1 | 2 | 3 |\n",
    "| `t1, t2 = f(1, 2)` | 1 | 2 | -1 |\n",
    "| `t1, t2 = f(1)` | 1 | 4 | -1 |\n",
    "| `t1, t2 = f(1, z=3)` | 1 | 4 | 3 |\n",
    "\n",
    "En principe, on doit s'assurer que les instructions composant le corps de la fonction mènent toujours à une instruction `return`, quels que soient les éventuels branchements conditionnels. Dans le cas contraire, la fonction renverra `None`, et on s'expose à des problèmes de typage."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    if x > 0:\n",
    "        return x\n",
    "\n",
    "print(f(1))\n",
    "print(f(-1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La première instruction `return` rencontrée interrompt immédiatement l'exécution de la fonction. On prendra garde à ne pas confondre `print` et `return`, la première se contentant de modifier l'affichage sans renvoyer de valeur."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    print(x)\n",
    "    x += 1\n",
    "    print(x)\n",
    "    x += 2\n",
    "    print(x)\n",
    "    x += 3\n",
    "    return x\n",
    "\n",
    "x = 0\n",
    "y = f(x)\n",
    "\n",
    "print(\"Résultats : x =\",x,\"et y =\",y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3.b Fonctions prédéfinies\n",
    "\n",
    "Voici une liste de quelques fonctions prédéfinies. \n",
    "\n",
    "| Fonction | Usage |\n",
    "|-|-|\n",
    "| `all(c)` ou `any(c)` | Indique si respectivement tous ou l'un des éléments du conteneur `c` convertis en booléens valent `True` |\n",
    "| `input(prompt = '')` | Demande à l'utilisateur d'entrer une valeur avec une invite optionnelle |\n",
    "| `len(c)` | Renvoie la longueur (`int`) du conteneur `c` |\n",
    "| `map(f, c)` | Renvoie le conteneur de même type que `c` contenant les valeurs de la fonction `f` appliquée aux éléments de `c` |\n",
    "| `min(c)` ou `max(c)` | Minimum et maximum d'un conteneur dont les éléments sont comparables entre eux |\n",
    "| `range(start = 0, stop, step = 1)` | Renvoie une liste contenant les entiers de `min` à `max` exclus par pas de longueur `step` |\n",
    "| `round(x, n = 0)` | Renvoie l'arrondi de la valeur numérique `x` sous flottante à (au plus) `n` chiffres décimaux après la virgule |\n",
    "| `sum(c)` | Renvoie la somme des éléments du conteneur `c` |\n",
    "| `type(x)` | Renvoie le type de `x` |\n",
    "\n",
    "Pour consulter la rubrique d'aide relative à une fonction, on peut utiliser la fonction `help`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "help(show)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3.c Les fonctions Lambda\n",
    "\n",
    "Les fonctions Lambda permettent de définir plus simplement les fonctions simples se définissant en une seule instruction. Elles peuvent avoir un ou plusieurs arguments et peuvent renvoyer n'importe quel type de données. \n",
    "Les exemples suivants vous montrerons simplement comment les utiliser. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "f = lambda x: x**2+1  # définit la fonction x-> x^2+1\n",
    "print(f(2))\n",
    "\n",
    "g=lambda x,y : x*y  # définit la fonction (x,y)-> x*y\n",
    "print(g(2,3))\n",
    "\n",
    "from math import sin\n",
    "h=lambda x: (sin(x)**2)  # définit la fonction x-> (sin x)^2\n",
    "print(h(2))\n",
    "\n",
    "k=lambda x:(x,2*x)  # définit la fonction x-> (x,2x)\n",
    "print(k(2))\n",
    "a,b=k(2)  # permet de stocker le résultat de k(2) dans le couple (a,b)\n",
    "print(a)\n",
    "print(b)\n",
    "\n",
    "applique=lambda u,x : u(x)  # applique la fonction u à x \n",
    "print(applique(f,2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.4 Structures de contrôle\n",
    "\n",
    "La structure syntaxique en Python est déterminée par les niveaux d'indentation du code.\n",
    "\n",
    "Les blocs de code relatifs à une structure de contrôle (boucle ou branchement conditionnel) sont introduits par le symbole `:` à la fin de la ligne qui précède et doivent être indentés d'un niveau supplémentaire par rapport au niveau parent. Le retour au niveau d'indentation précédent signale au compilateur la fin du bloc.\n",
    "\n",
    "\n",
    "En principe, on indente de quatre espaces supplémentaires à chaque niveau. Ceux-ci peuvent être obtenus facilement grâce à la touche de tabulation.\n",
    "\n",
    "### 1.2.a Branchements if\n",
    "\n",
    "La syntaxe générale est\n",
    "\n",
    "```python\n",
    "if condition1:\n",
    "    instructions\n",
    "elif condition2:\n",
    "    instructions\n",
    "elif condition3:\n",
    "    instructions\n",
    "else:\n",
    "    instructions\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2.b Boucles for (itération)\n",
    "\n",
    "La syntaxe générale d'une boucle for est \n",
    "\n",
    "```python\n",
    "for variable in liste:\n",
    "    instructions\n",
    "```\n",
    "\n",
    "Notez que l'instruction `range(a,b)` construit une liste des entiers compris entre `a` et `b-1`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2.c Boucles while (itération)\n",
    "\n",
    "La syntaxe générale d'une boucle While est \n",
    "\n",
    "```python\n",
    "while condition:\n",
    "    instructions\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# La fonction suivante cherche le premier élément négatif dans une liste. Elle renvoie 1 si elle n'en trouve pas.\n",
    "\n",
    "def premier_negatif(l):\n",
    "    n = len(l)\n",
    "    k = 0\n",
    "    while (k<n) and (l[k]>=0):\n",
    "        k+=1\n",
    "    if k==n:\n",
    "        return 1\n",
    "    else:\n",
    "        return l[k]\n",
    "\n",
    "l = [6,2,-3,7,-4]\n",
    "print(premier_negatif(l))\n",
    "\n",
    "l = [6,2,3,7,4]\n",
    "print(premier_negatif(l))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. Bibliothèques Python\n",
    "\n",
    "## 2.1 La bibliothèque `numpy` de calcul scientifique\n",
    "\n",
    "La bibliothèque `numpy` introduit le type `ndarray` ainsi que de nombreuses fonctions de calcul flottant notamment. On peut l'importer de plusieurs façon :\n",
    "\n",
    "+   Sous un nom abrégé : `import numpy as np`. On devra alors préfixer les fonctions ainsi importées. La racine carrée s'utilisera `np.sqrt(2)`.\n",
    "+   Sans préfixage : `from numpy import *`. Dans ce cas on écrira `sqrt(2)`.\n",
    "\n",
    "Si vous utilisez la commande `%pylab inline`, la bibliothèque numpy sera importé sans préfixage. Celle-ci est spécialisée dans la manipulation des tableaux `array`. On l'utilisera pour manipuler des vecteurs et des matrices.\n",
    "\n",
    "+  Les tableaux `numpy` ne gèrent que les objets de même type\n",
    "+  La bibliothèque `numpy` propose un grand nombre de routines pour un accès rapide aux données (ex. recherche, extraction), pour les manipulations diverses (ex. tri), pour les calculs (ex. calcul statistique et scientifique, calcul élément par élément, calcul matriciel)\n",
    "+  Les tableaux `numpy` sont plus performants (rapidité, gestion de la volumétrie) que les itérables usuel de Python (listes, tuples...)\n",
    "+  Les tableaux `numpy` sont sous-jacents à de nombreux packages dédiés au calcul scientifique sous Python.\n",
    "+  Une matrice est un tableau (array) à 2 dimensions (lignes et colonnes), un vecteur est un tableau (array) avec une seule ligne\n",
    "+  À la différence d'autres langages classiques, la plupart des opérateurs $(+, *, **, etc.)$ agissent élément par élément sur les tableaux.\n",
    "\n",
    "Pour plus d'infos sur cette bibliothèque  : \n",
    "http://docs.scipy.org/doc/numpy/reference/index.html\n",
    "\n",
    "### 2.1.a Les vecteurs \n",
    "\n",
    "On utilise pour créer des vecteurs `numpy` les matrices avec une seule ligne.\n",
    "\n",
    "<font color=red>Attention :</font> la numérotation pour l'indexation se fait à partir de 0, c'est-à -dire que le premier élément est numéroté 0 et non 1. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "%pylab inline\n",
    "\n",
    "A = array([[1,2,3],[4,5,6],[7,8,9]])\n",
    "print(\"A =\",A)\n",
    "print(\"A est de type\",type(A)) # type ndarray \n",
    "print(\"A est de taille\",shape(A))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Création de vecteur ligne: \n",
    "l = array([5, 4, 3])\n",
    "print(\"l =\",l)\n",
    "print(\"l est de type\",type(l)) # type ndarray \n",
    "print(\"l est de taille\",size(l))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Création de vecteur colonne: \n",
    "c = array([[5], [4], [3]])\n",
    "print(\"c =\",c)\n",
    "print(\"c est de type\",type(c)) # type ndarray \n",
    "print(\"c est de taille\",size(c))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Produit matriciels, attention aux dimensions !\n",
    "print(dot(A,c))\n",
    "print(dot(l,A))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Indexation, accès\n",
    "T = array([8, 7, 6, 5, 4, 3, 2, 1, 0])\n",
    "print(T[2])                          # attention l'indice 2 correspond au 3eme élément (numérotation à partir de 0).\n",
    "print(T[3:7])                        # attention dans la syntaxe a:b, les indices vont de a jusqu'à b-1.\n",
    "print(T[:5])                         # accès à tous les éléments avant l'indice 2. La syntaxe T[2:] fonctionne aussi.\n",
    "\n",
    "index = [5,7,4]\n",
    "print(T[index])                      # on peut étendre la syntaxe à n'importe quelle liste d'indices.\n",
    "print(T>2)                           # crée la liste des booléens T[k]>2 \n",
    "print(T[T > 2])                      # extrait de T ses éléments strict. plus grands que 2\n",
    "\n",
    "T[T > 2] *= -1                       # multiplie par -1 les éléments strict. plus grands que 2 du vecteur\n",
    "print(T)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Création d'un maillage d'un segment.\n",
    "# avec un pas entier...\n",
    "a=arange(1,10)\n",
    "b=arange(start=10,stop=0,step=-2)\n",
    "c=arange(10)\n",
    "print(\"Subdivisions entières :\")\n",
    "print(a)\n",
    "print(b)\n",
    "print(c)\n",
    "\n",
    "# ... ou avec un pas plus fin, pour obtenir une subdivision uniforme de [a,b] avec un pas h.\n",
    "# ATTENTION b n'est pas inclus !!\n",
    "c=arange(0,1,0.1)\n",
    "d=arange(start=0.2,stop=1.2,step=0.3)\n",
    "print(\"\\nSubdivisions fine sans extrémité droite\")\n",
    "print(c)\n",
    "print(d)\n",
    "\n",
    "# Une variante ou l'éxtrémité droite est inclue. Crée une subdivision uniforme de [a,b] avec n éléments.\n",
    "# ATTENTION b EST INCLUS CETTE FOIS !!!!\n",
    "n=10\n",
    "print(\"\\nSubdivision fine avec extrémité droite\")\n",
    "print(linspace(0,1,n+1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# vecteur de 1.\n",
    "a=ones(5)\n",
    "print(a)\n",
    "b=full(5,3.2) # crée un vecteur de 5 éléments égaux à 3.2\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# ATTENTION Duplication !!!\n",
    "print(\"Mauvaise copie, changer t2 a un impact sur t1.\")\n",
    "t1 = array([1, 2, 3, 4])\n",
    "t2 = t1[1:3]    # Pas de duplication, toute modification de t2 aura un effet sur t1\n",
    "print(t1)\n",
    "print(t2)\n",
    "t2[0] = 5\n",
    "print(t2)\n",
    "print(t1)\n",
    "\n",
    "print(\"\\nBonne copie, t1 et t2 sont décorélés\")\n",
    "t1 = array([1, 2, 3, 4])\n",
    "t2=copy(t1[1:3])\n",
    "print(t1)\n",
    "print(t2)\n",
    "t2[0] = 5\n",
    "print(t2)\n",
    "print(t1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1.b Les matrices \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La bibliothèque `numpy` fournit des fonctions pour créer et gérer facilement des tableaux à plusieurs dimensions.\n",
    "\n",
    "| Fonction | Usage |\n",
    "|-|-|\n",
    "| `arange(start=0, stop, step=1)` | Similaire à `range`, mais renvoie un tableau et les arguments peuvent être de type flottant |\n",
    "| `linspace(start, stop, n=50)` | Renvoie un tableau à `n` valeurs uniformément réparties entre `start` et `stop` (bornes incluses) |\n",
    "| `array(c)` | Crée un tableau à partir du conteneur `c`. Le type des éléments peut aussi être choisi. |\n",
    "| `zeros(shape)` `ones(shape)` | Crée un tableau de la forme désirée, rempli de zéros ou de uns. Le type des éléments peut aussi être choisi. |\n",
    "| `identity(n)` | Crée une matrice identité de taille $n\\times n$ |\n",
    "| `diag(A)` | Diagonale d'une matrice (si `A` est bidimensionnel) ou matrice diagonale (si `A` est monodimensionnel) |\n",
    "| `dot(A, B)` | Produit matriciel |\n",
    "| `reshape(T, shape)` | Renvoie le tableau obtenu en réarrangeant le tableau selon une nouvelle forme |\n",
    "| `concatenate(l)` | \"Concatène\" une liste de tableaux entre eux |\n",
    "| `roll(a, shift)` | Effectue une permutation circulaire des éléments d'un tableau en décalant les éléments vers la droite (les derniers reviennent à gauche) |\n",
    "| `meshgrid(range(m), range(n))` | Renvoie deux matrices $m\\times n$, la première contenant les indices des lignes, la seconde ceux des colonnes. Utile pour créer une matrice à partir de son terme général |\n",
    "| `fromfunction(f, shape)` | Crée un tableau à partir d'une fonction |\n",
    "| `fromfile(filename, dtype)` | Création depuis un fichier. L'inconvénient par rapport à `tofile` est qu'il faut préciser le type des éléments (`dtype`) et la forme est perdue (le tableau obtenu n'aura qu'une seule dimension, comme s'il avait subi `flatten()`) |\n",
    "\n",
    "Attention, la produit matriciel ou les puissances des matrices ne s'obtiennent pas avec les multiplication et l'exponenciation classique (ces opérations se fonct élément par élément)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "A = identity(2, int)\n",
    "B = array([[1, 2], [3, 4]])\n",
    "print(A)\n",
    "print(B)\n",
    "print(A * B)\n",
    "print(dot(A, B))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1.c  Fonctions introduites par `numpy`\n",
    "\n",
    "La bibliothèque `numpy` introduit ou redéfinit un grand nombre de fonctions numériques. Celles-ci peuvent agir sur des valeurs numériques individuelles, ou sur des tableaux (ou listes) élément par élément. En voici quelques-unes.\n",
    "\n",
    "| Fonction | Usage |\n",
    "|-|-|\n",
    "| `numpy.abs` `conj` `real` `imag` `angle` | Module, conjugué, partie réelle, partie imaginaire, argument |\n",
    "| `cos` `sin` `tan` `sinh` `cosh` `tanh` |  |\n",
    "| `arccos` `arcsin` `arctan` `arcsinh` `arccosh` `arctanh` |  |\n",
    "| `exp` `log` |  |\n",
    "| `numpy.round` `floor` `ceil` | Arrondi au plus proche, arrondi inférieur, arrondi supérieur |\n",
    "\n",
    "Elle introduit également de nombreuses fonctions spécifiques aux tableaux. En voici une petite liste.\n",
    "\n",
    "| Fonction | Usage |\n",
    "|-|-|\n",
    "| `sum` `prod` | Somme et produit des éléments |\n",
    "| `numpy.min` `numpy.max` `mean` `median` `std` | Minimum, maximum, moyenne, médiane, écart-type |\n",
    "| `cumprod` `cumsum` | Produit ou somme cumulés |\n",
    "| `argmin` `argmax` `argsort` | Indice du minimum, du maximum, tableau d'indices permettant de trier le tableau |\n",
    "| `convolve` | Convolution discrète |\n",
    "\n",
    "Mentionnons encore quelques constantes utiles: `pi`, `e`, `inf`, `nan`, etc.\n",
    "\n",
    "\n",
    "**Attention**: importer `numpy` dans l'espace de base sans préfixe (`from numpy import *`) ne remplace pas les fonctions prédéfinies de Python (`min`, `max`, `abs`...). On devra donc les préfixer si on souhaite utiliser la version `numpy`. Cela n'a en général pas d'importance, sauf pour `min`, `max` et `round`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "t = array([[1, 2, 3, 4],[2,3,1,5]])\n",
    "\n",
    "print(np.max(t))                       # fonctionne.\n",
    "print(max(t))                          # ne fonctionne pas."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1.d Fonctions introduites par `numpy.linalg`\n",
    "\n",
    "| Fonction | Usage |\n",
    "|-|-|\n",
    "| `dot(A, B)` | Produit matriciel |\n",
    "| `matrix_power(M, n)` | Exposant matriciel |\n",
    "| `norm(x)` | Norme (euclidienne par défaut) d'un vecteur |\n",
    "| `det(A)` `tr(A)` | Déterminant et trace |\n",
    "| `eig(A)` `eigvals(A)` | Vecteurs et valeurs propres |\n",
    "| `matrix_rank(A)` | Rang d'une matrice |\n",
    "| `solve(A, b)` | Résolution du système linéaire $Ax=b$ |\n",
    "| `inv(A)` | Inversion matricielle |\n",
    "| `cholesky(A)` | Décomposition de Cholesky |\n",
    "| `qr(A)` | Décomposition QR |\n",
    "\n",
    "D'autres fonctions sont décrites sur http://docs.scipy.org/doc/numpy/reference/routines.linalg.html."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# On peut importer les bibliothèque par des préfixes si on veut se souvenir d'où vient chaque fonction.\n",
    "import numpy.linalg as nl\n",
    "import numpy as np\n",
    "\n",
    "A = np.array([[2, 3, 5, 7],\n",
    "           [11, 13, 17, 19],\n",
    "           [23, 29, 31, 37],\n",
    "           [41, 43, 47, 53]])\n",
    "\n",
    "print(nl.det(A),np.trace(A))\n",
    "eigenvalues, eigenvectors = nl.eig(A)\n",
    "print(eigenvalues)\n",
    "print(eigenvectors)\n",
    "# On calcule inv(P).A.P\n",
    "print(np.round(np.dot(np.dot(nl.inv(eigenvectors), A), eigenvectors), 10))\n",
    "v = nl.solve(A, [1, 2, 3, 4])\n",
    "print(np.dot(A, v))\n",
    "print(v)\n",
    "\n",
    "# Pour une version sans préfixe, utiliser plutôt from ... import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.2 La bibliothèque `Matplotlib.pyplot`\n",
    "\n",
    "La bibliothèque `matplotlib` (et sa sous-bibliothèque pyplot) sert essentiellement à afficher des graphismes. Son utilisation ressemble beaucoup à celle de Matlab. Traditionnellement, on l'importe:\n",
    "\n",
    "+   soit directement dans l'environnement courant (`from matplotlib.pyplot import *`);\n",
    "+   soit sous un nom abrégé (`import matplotlib.pyplot as plt`).\n",
    "\n",
    "Dans ce qui suit, on suppose qu'on utilise le backend `inline`, propre aux notebooks. Si on utilise un autre backend, il pourra être nécessaire d'ajouter `show()` à la fin des commandes pour faire apparaitre la fenêtre qui contient le dessin.\n",
    "\n",
    "Voici une courte liste de commandes possibles.\n",
    "\n",
    "| Commande | Effet |\n",
    "|-|-|\n",
    "| plot(y) | Affiche les points dont les ordonnées sont dans `y` |\n",
    "| plot(x, y) | Affiche les points de coordonnées $(x_k,y_k)$ |\n",
    "| matshow(a) | Affiche une matrice |\n",
    "| imshow(a) | Idem, mais avec plus d'options (et la possibilité de faire des sous-figures) |\n",
    "| hist(y, bins=10) | Affiche un histogramme de la répartition des valeurs des $y_k$. On peut choisir le nombre de barres, voire leurs bornes |\n",
    "| figure() | Commence une nouvelle figure (si on ne l'a pas fait, cette fonction est appelée implicitement dès qu'on commence à afficher quelque chose) |\n",
    "| figure(figsize=(a,b)) | Idem, mais permet d'imposer une taille (en pouces) à la figure |\n",
    "| subplot(lines, columns, index) | Indique qu'on va commencer une sous-figure |\n",
    "| suptitle(\"titre\") | Afficher un titre au-dessus de la figure. Attention aux caractères accentués (précéder la chaîne du préfixe `u`). Il est possible de mettre du LaTeX entre dollars `$` |\n",
    "| legend() | Afficher les légendes (s'il y en a) |\n",
    "| axis([xmin, xmax, ymin, ymax]) | Définit explicitement la taille des axes. Par défaut, ceux-ci s'adaptent automatiquement à la taille du contenu de la figure |\n",
    "| axis(\"scaled\") | Indique que le repère doit être orthonormé (pas de distorsion à l'affichage). À utiliser **après** `plot(...)` car son utilisation désactive l'ajustement automatique des axes |\n",
    "| axis(\"off\") | Ne pas afficher les axes |\n",
    "| loglog() | Passer en échelle log-log |\n",
    "\n",
    "La fonction `plot` (la plus utilisée) peut prendre une grande variété de paramètres supplémentaires pour contrôler l'aspect des courbes tracées. Par défaut, les points sont reliés par des segments. Voici quelques paramètres optionnels possibles:\n",
    "\n",
    "-   `linestyle=s`, avec `s` qui vaut par exemple\n",
    "    -   `\"solid\"` ou `\"-\"` (lignes pleines),\n",
    "    -   `\"dashed\"` ou `\"--\"` (tirets),\n",
    "    -   `\"dotted\"` ou `\":\"` (pointillés),\n",
    "    -   `\"\"` (pas de lignes);\n",
    "-   `color=c`, avec `c` qui vaut par exemple `\"red\"`, `\"green\"`, `\"blue\"` etc.\n",
    "-   `marker=m`, avec `m` qui vaut par exemple\n",
    "    -   `\"\"` (pas de marqueur);\n",
    "    -   `\",\"` (petits points),\n",
    "    -   `\".\"` (gros points),\n",
    "    -   `\"+\"` ou `\"x\"` (croix),\n",
    "    -   `\"*\"` (étoiles),\n",
    "    -   `\"o\"` (cercles),\n",
    "    -   `\"s\"` (carrés);\n",
    "-   `markersize=s` pour contrôler la taille des marqueurs;\n",
    "-   `legend=l` où `l` est une chaîne de caractères pour donner un titre à la courbe. Celui-ci n'apparaitra que si l'on utilise `legend()` par la suite. Mêmes remarques que pour `suptitle`.\n",
    "\n",
    "On peut aussi utiliser l'écriture `plot(x, y, \"style\")` où `style` est donné sous forme abrégée, par exemple:\n",
    "\n",
    "-   `\"y-x\"` pour des croix reliées par des lignes jaunes;\n",
    "-   `\"g:*\"` pour des étoiles reliées par des pointillés verts;\n",
    "-   `\"bo\"` pour des cercles bleus sans lignes;\n",
    "-   `\"c-\"` pour des lignes cyans sans marqueur.\n",
    "\n",
    "Une vaste liste de fonctions supplémentaires et d'exemples illustrés peut se trouver à la page http://matplotlib.org/index.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "%pylab inline \n",
    "# permet d'importer numpy et matplotlib.pyplot\n",
    "\n",
    "plot([0,1,-1,2,-2,3,-3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Représentation d'une suite\n",
    "\n",
    "n = arange(50)\n",
    "u = (-1) ** n * exp(-n / 20.)\n",
    "plot(u, \"r+\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Représentation d'un graphe de fonction\n",
    "\n",
    "x = linspace(-5 * pi, 5 * pi, 200)\n",
    "y = sin(x) / x\n",
    "plot(x, y, \"g\", label='$\\\\frac{\\\\sin x}{x}$')    # Ici il faut échapper le caractère \\\n",
    "legend()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Représentation d'une courbe paramétrée\n",
    "\n",
    "t = linspace(0, 2 * pi, 500)\n",
    "x = cos(t)\n",
    "y = sin(t) + sqrt(abs(cos(t)))\n",
    "plot(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Echelle logarithmique\n",
    "\n",
    "figure(figsize=(13,5))\n",
    "\n",
    "t = linspace(0, 2, 100)\n",
    "x = 2 ** t\n",
    "y = 1 / x ** 3\n",
    "\n",
    "subplot(1, 2, 1)\n",
    "title('Echelle lineaire')    # Pour les chaîne avec caractères accentués, mettre un préfixe u avant le guillemets\n",
    "plot(x, y)\n",
    "\n",
    "subplot(1, 2, 2)\n",
    "title('Echelle logaritmique')\n",
    "plot(log(x), log(y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "from numpy import *\n",
    "from numpy.linalg import *\n",
    "from scipy.linalg import *\n",
    "from matplotlib.pyplot import *\n",
    "%pylab inline "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Applications\n",
    "\n",
    "<font color=black>**Exercice 1 : petits systèmes, conditionnement et stabilité**</font>\n",
    "\n",
    "On considère les sytèmes linéaires perturbés suivants, étudiés en TD: \n",
    "$$\n",
    "A=\\left (\n",
    "\\begin{array}{cc}\n",
    "7 & 10 \\\\\n",
    "5 & 7\n",
    "\\end{array}\n",
    "\\right ), \\quad Y_{1}= \n",
    "\\left (\n",
    "\\begin{array}{c}\n",
    "10 \\\\\n",
    "7\n",
    "\\end{array}\n",
    "\\right ) \\quad \\textrm{et} \\quad Y_{2}=\n",
    "\\left ( \n",
    "\\begin{array}{cc}\n",
    "10,1 \\\\\n",
    "6,9\n",
    "\\end{array}\n",
    "\\right ).\n",
    "$$\n",
    "\n",
    "Résoudre les équations $AX=Y1$ et $AX=Y2$ à l'aide de la commande `solve` de la librairie `numpy.linalg`. Calculer le conditionnement de $A$ et conclure. \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 1.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=black>**Exercice 2 : normes subordonnées**</font>\n",
    "\n",
    "On considère la matrice $A=\\left(\\begin{array}{cccc}2 & 1 & 1 & 0 \\\\4 & 3 & 3 & 1 \\\\8 & 7 & 9 & 5 \\\\6 & 7 & 9 & 8\\end{array}\\right)$. En utilisant la commande `norm`, calculer ses normes $\\|\\|_1$, $\\|\\|_2$ et $\\|\\|_{\\infty}$.\n",
    "\n",
    "Écrire vos propres fonction `norme_1`, `norme_2` et `norme_inf` de manière la plus concise possible à partir des fonctions pré-programmée de Python, en utilisant les formules suivantes vues en cours et TD:\n",
    "- $\\|A\\|_{\\infty}=\\max_{i\\in\\{1,...,N\\}}\\sum_{j=1}^{N} |a_{i,j}|$\n",
    "- $\\|A\\|_{1}=\\max_{j\\in\\{1,...,N\\}}\\sum_{i=1}^{N} |a_{i,j}|$\n",
    "- $\\|A\\|_{2}=(\\rho(A^{T}A))^{\\frac{1}{2}}$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 2.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color = black> **Exercice 3 : les anniversaires**</font> \n",
    "\n",
    "Écrire un programme `calendrier(nom, jour, mois, année)` qui affiche la phrase `Hugo est né(e) le 28 février 1966` lorsque appelée avec les arguments `nom=\"Hugo\", jour=\"28\", mois=\"février\", année=\"1966\"`, et qui renvoie l'âge qu'aurait Hugo si nous étions le jour de son anniversaire de l'année 2020. On imposera le 01/01/2000 comme date d'anniversaire par défaut."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 3.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color = black>**Exercice 4 : la composition**</font> \n",
    "\n",
    "En utilisant les fonctions lambda, écrire une fonction `h=compose(f,g)`, qui prend en argument deux fonctions, et renvoie une fonction telle que `h(x) = f(g(x))`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 4.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color = black>**Exercice 5 : le signe d'un réel**</font><br>\n",
    "Écrire une fonction `signe(x)` qui prend en argument un flottant, et affiche s'il est positif, négatif ou nul sous la forme d'une phrase. Si `x=2`, on veut afficher `\"Le réel 2 est positif.\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 5.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color = black>**Exercice 6 : Somme des entiers pairs**</font><br>\n",
    "Écrire un programme qui calcule la somme des entiers pairs inférieurs à 50."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 6.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color = black>**Exercice 7 : plots**</font>\n",
    "\n",
    "Sur la même figure contenant deux graphiques, tracer les graphes de deux fonctions trigo $f_1$, $f_2$ de votre choix. Calculer les termes des suites $u_{n+1} = f_1(u_n)$ et $v_{n+1} = f_2(v_n)$, et les afficher sur le graphe de la fonction associée."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# Exercice 7.\n"
   ]
  }
 ],
 "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.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
