\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"id": "23c00ef1",
"metadata": {},
"source": [
"Vous avez découverts les tableaux `numpy.ndarray` dont nous vous redonnons quelques méthodes:"
]
},
{
"cell_type": "markdown",
"id": "82433309",
"metadata": {},
"source": [
"| les méthodes | ce qu'elles font |\n",
"|--------------------------|--------------------------------------------------|\n",
"| `np.ndarray.size` | le nombre d'éléments du tableau |\n",
"| `np.ndarray.itemsize` | la taille en octet d'un élément |\n",
"| `np.ndarray.nbytes` | la taille totale du tableau sous-jacent en octet |\n",
"| `np.ndarray.shape` | la forme du tableau (tuple) |\n",
"| `np.ndarray.ndim` | le nombre de dimensions du tableau |\n",
"| `np.ndarray.dtype` | le type des éléments |"
]
},
{
"cell_type": "markdown",
"id": "1fda98e3",
"metadata": {},
"source": [
"Nous allons maintenant rapidement aborder le sujet de la mémoire sur laquelle les tableaux `numpy.ndarray` sont stockés."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "e8ef2ded",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "markdown",
"id": "52712f22",
"metadata": {},
"source": [
"Un petit aparté vers ceux qui se demandent \n",
"> à quoi cela peut bien me servir d'avoir une intuition de la manière dont la librarie `numpy` travaille en mémoire ?!\n",
"\n",
"Une première raison: afin que vous preniez des décisions en connaissance de cause ou du moins en essayant de comprendre les conséquences de vos choix.\n",
"\n",
"Une seconde raison: afin que vous ne soyez pas complètement dépourvus le jour où vos codes, en se complexifiant, deviendront beaucoup trop lents ou prendront trop d'espace mémoire pour traiter vos données ...\n",
"\n",
"Une troisième raison: afin de vous familiariser avec l'informatique et comprendre des mécanismes sous-jacents qui expliquent les choix des concepteurs de libraries.\n",
"\n",
"Une dernière raison, afin d'avoir une petite culture informatique technique bien formée pour ne jamais penser que c'est magique, incompréhensible ou trop compliqué ! \n",
"Donc si vous ne comprenez pas bien une notion, vous le dites !\n",
"et on vous l'explique"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5d6b741b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# une cellule pour définir le style de présentation \n",
"# utilisé dans la suite pour les dessins de la mémoire\n",
"\n",
"my_stylesheet = \"\"\n",
"\n",
"from IPython.display import HTML\n",
"HTML(my_stylesheet)"
]
},
{
"cell_type": "markdown",
"id": "a218e1f3",
"metadata": {},
"source": [
"# numpy et la mémoire"
]
},
{
"cell_type": "markdown",
"id": "03cf05d6",
"metadata": {},
"source": [
"Reprenons notre matrice du notebook précédent:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5a183bb3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 1, 2, 3, 4, 5],\n",
" [ 6, 7, 8, 9, 10],\n",
" [11, 12, 13, 14, 15],\n",
" [16, 17, 18, 19, 20]])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"matrice = [\n",
" [1, 2, 3, 4, 5], \n",
" [6, 7, 8, 9, 10],\n",
" [11, 12, 13, 14, 15],\n",
" [16, 17, 18, 19, 20]\n",
"]\n",
"mat = np.array(matrice)\n",
"mat"
]
},
{
"cell_type": "markdown",
"id": "55697dda",
"metadata": {},
"source": [
"Notre matrice contient 20 éléments:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "0772a882",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"20"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mat.size"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ff395569",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('int64')"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mat.dtype"
]
},
{
"cell_type": "markdown",
"id": "1d05b2ca",
"metadata": {},
"source": [
"Chaque élément est codé sur un `numpy.int64` et occupe donc 8 octets:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5694071d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mat.itemsize"
]
},
{
"cell_type": "markdown",
"id": "3f9c825b",
"metadata": {},
"source": [
"Donc la mémoire qu'occupe la matrice en nombre d'octets est $20 \\times 8$:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "4be4d0e2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"160"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mat.nbytes # byte = otet"
]
},
{
"cell_type": "markdown",
"id": "3ae98ab3",
"metadata": {},
"source": [
"Nous allons maitenant nous intéresser à la manière dont est représentée cette mémoire dans l'ordinateur lorsque la matrice est créée."
]
},
{
"cell_type": "markdown",
"id": "aa8dc0f9",
"metadata": {},
"source": [
"## organisation de la mémoire des tableaux"
]
},
{
"cell_type": "markdown",
"id": "299a3386",
"metadata": {},
"source": [
"Lisons le help (en faisant ```help(np.ndarray)``` ou directement ```np.ndarray?``` dans un notebook), il vous dit que votre `np.ndarray` est un tableau:\n",
" 1. **multidimensionnel**\n",
" 1. **homogène**\n",
" 1. d'éléments de **taille fixe**\n",
" 1. et que les tableaux doivent être construits en utilisant les méthodes `np.array`,`np.zeros` ou `np.empty`"
]
},
{
"cell_type": "markdown",
"id": "ff4f5200",
"metadata": {},
"source": [
"Bon déjà que les tableaux soient **multidimensionnel**s ça nous rassure: ils sont là pour cela !"
]
},
{
"cell_type": "markdown",
"id": "804d3fea",
"metadata": {},
"source": [
"Qu'on les crée avec les méthodes `np.array`,`np.zeros` ou `np.empty`, on l'a vu."
]
},
{
"cell_type": "markdown",
"id": "aff329c0",
"metadata": {
"tags": [
"level_basic"
]
},
"source": [
"Mais que veut bien dire que les tableaux sont homogènes ? Une idée ? Dans les exemples que nous avons vus ?"
]
},
{
"cell_type": "markdown",
"id": "6948a331",
"metadata": {},
"source": [
"Vous avez commencé à vous en rendre compte avec les tableaux que nous avons construits. Ce qui est homogène c'est le type des éléments. Toutes les cases du tableau ayant le même type, elles occupent la même taille en mémoire."
]
},
{
"cell_type": "markdown",
"id": "3c83f7de",
"metadata": {
"tags": [
"level_basic"
]
},
"source": [
"Et que veut-dire que tous les éléments sont de **taille fixe** ?"
]
},
{
"cell_type": "markdown",
"id": "b40559cd",
"metadata": {
"tags": []
},
"source": [
"Ca veut dire qu'une fois le tableau créé, vous n'allez pas pouvoir modifier la taille de ses éléments (la place sur laquelle chaque élément est stocké en mémoire). Si vous avez besoin de modifier la taille des éléments que contient un tableau, vous devez faire un nouveau tableau. On y revient bientôt."
]
},
{
"cell_type": "markdown",
"id": "ecf4f1ec",
"metadata": {},
"source": [
"A quoi servent toutes ces restrictions ?\n",
"\n",
"Vous avez là les ingrédients qui permettent à `numpy` d'être très rapide dans sa manipulation de tableaux !"
]
},
{
"cell_type": "markdown",
"id": "ce56f615",
"metadata": {
"tags": []
},
"source": [
"### les secrets de la rapidité des tableaux `numpy` (avancé mais important)"
]
},
{
"cell_type": "markdown",
"id": "aaae33e4",
"metadata": {
"tags": [
"level_basic"
]
},
"source": [
"Quels sont les secrets d'un code rapide sur des tableaux ? Des idées ? C'est un peu difficile parce qu'on doit mettre (un peu) les mains dans le cambouis (ici la mémoire) et mais vous pouvez proposer des idées ! J'en vois déjà un:"
]
},
{
"cell_type": "markdown",
"id": "188f0a2d",
"metadata": {},
"source": [
"#### premier secret (*offset*)"
]
},
{
"cell_type": "markdown",
"id": "53c7f0aa",
"metadata": {
"tags": []
},
"source": [
"C'est la possibilité quand on est sur un élément d'un tableau de passer très rapidement à un autre élément du même tableau.\n",
"\n",
"Comment fait-on cela ?"
]
},
{
"cell_type": "markdown",
"id": "791d14e7",
"metadata": {
"tags": []
},
"source": [
"Et bien si toute la zone mémoire du tableau est composée d'un unique block mémoire continu \n",
"(c-à-d si les cases du tableaux sont contiguës en mémoire) ... \n",
"\n",
"passer d'une case à une autre (d'un élément à un autre) se fait alors grâce à un simple décalage - appelé *offset*(\\*) \n",
"et les ordis font ca super super vite !\n",
"\n",
"\n",
"\n",
"(\\*) Je plagie Wikipédia: *l'offset désigne une adresse de manière relative. C'est une valeur entière représentant le déplacement en mémoire nécessaire, par rapport à une adresse de référence, pour atteindre une autre adresse. Autrement dit, l'offset est la distance séparant deux emplacements mémoire.*"
]
},
{
"cell_type": "markdown",
"id": "f86b2424",
"metadata": {
"tags": []
},
"source": [
"Voici des cases mémoire contiguës en mémoire qui forment un tableau.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"id": "5da6993f",
"metadata": {
"tags": []
},
"source": [
"Voici des cases mémoire un peu partout (pour tenter de décrire le type de fragmentation qu'on obtient quand on utilise des types de base de Python, comme par exemple une liste de listes)\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"id": "0ac5c762",
"metadata": {
"tags": []
},
"source": [
"L'ordi va se déplacer beaucoup plus rapidement pour passer d'un élément à un autre \n",
"si les éléments sont continuës \n",
"que si les éléments du tableau sont dissiminés un peu partout dans la mémoire \n",
"(comme c'est le cas dans certaine stuctures de données, par exemple les listes chaînées)."
]
},
{
"cell_type": "markdown",
"id": "7777d530",
"metadata": {},
"source": [
"Et pour cela il faut que la taille des éléments du tableau soit fixe."
]
},
{
"cell_type": "markdown",
"id": "f50b44c5",
"metadata": {},
"source": [
"#### second secret (*pas d'indirection*)"
]
},
{
"cell_type": "markdown",
"id": "0bc11164",
"metadata": {},
"source": [
"Un second secret, c'est que `numpy` quand il arrive dans une case du tableau: il y trouve la valeur qu'il cherche \n",
"(on parle là de nos exemples avec des nombres)."
]
},
{
"cell_type": "markdown",
"id": "5d3f9760",
"metadata": {
"tags": [
"level_advanced"
]
},
"source": [
"Quelques mots sur les listes Python pour ceux qui sont avancés:\n",
"\n",
"Les listes Python sont en fait codées sous la forme de tableaux (i) qui peuvent changer de taille, (ii) dont les éléments sont de type hétérogène, (ii) où vous pouvez modifier ou rajouter un élément de n'importe quel type sans que les autres éléments ne soient touchés...\n",
"\n",
"En informatique, un tableau est une zone mémoire qui est continue en mémoire, toujours. Voila un exemple de tableau de 3 cases:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "67bdbdca",
"metadata": {
"tags": [
"level_advanced"
]
},
"outputs": [
{
"data": {
"text/plain": [
"[1, 12345678235234501256848345678901234567890264378034, 3.141592653589793]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"t3 = [ 1, True, np.pi]\n",
"t3[1] = 12345678235234501256848345678901234567890264378034\n",
"t3"
]
},
{
"cell_type": "markdown",
"id": "79e8c19e",
"metadata": {
"tags": [
"level_advanced"
]
},
"source": [
"Donc, si les cases d'un tableau en informatique ont toujours la même taille, comment vais-je y \"*mettre*\" des élément hétérogènes ? Des idées ?"
]
},
{
"cell_type": "markdown",
"id": "1a5918ee",
"metadata": {
"tags": [
"level_advanced"
]
},
"source": [
"Oui nous allons utiliser des adresses ! on va mettre dans la case, l'adresse de l'endroit où se trouve l'élément en mémoire.\n",
"\n",
"Toutes les adresses sont codées sur le même nombre d'octets. Combien ? J'espère 8 octets (64 bits) ! heu vous avez un ordi 32-bits ... c'est qui qui vous l'a prêté ?\n",
"\n",
"Quand on arrive sur un élément et qu'on *trouve* sur une adresse, pour y aller lire la valeur, nous n'avons pas un simple offset à faire mais bien une indirection et c'est beaucoup beaucoup plus long..."
]
},
{
"cell_type": "markdown",
"id": "fbecd2e5",
"metadata": {},
"source": [
"### taille fixe des éléments"
]
},
{
"cell_type": "markdown",
"id": "ac95237e",
"metadata": {},
"source": [
"Pour illustrer le fait que la taille des éléments est fixe dans un tableau `numpy`, vous allez faire un petit exercice: créer un tableau `numpy` de chaînes de caractères."
]
},
{
"cell_type": "markdown",
"id": "19a79070",
"metadata": {},
"source": [
"À vous de jouer. Voici une liste python des jours de la semaine. Construisez une `numpy.ndarray` avec cette liste.\n",
"\n",
"Affichez le type que `numpy` a choisi comme type pour les éléments. Rappelez-vous tous les éléments vont-être du même type ! Donc toutes les chaînes de caractères vont avoir le même type."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "b7f57d5c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"str"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"les_jours = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']\n",
"type(les_jours[0])"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "b26ff0b5",
"metadata": {},
"outputs": [],
"source": [
"# votre code ici (correction ci-dessous, ne pas regarder tout de suite !)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "a469cc92",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# solution\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ml\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mValueError\u001b[0m: could not convert string to float: 'bonjour'"
]
}
],
"source": [
"# solution\n",
"np.array(l, dtype=np.float)"
]
},
{
"cell_type": "markdown",
"id": "b09b6366",
"metadata": {},
"source": [
"Qu'avez-vous eu ? Oui une erreur `ValueError` lorsque `numpy` a essayé de convertir 'bonjour' en un entier ... bon il arrive à faire les conversions évidentes et là il n'en trouve pas !"
]
},
{
"cell_type": "markdown",
"id": "8430cbb1",
"metadata": {},
"source": [
"Il existe des types prédéfinis, regardez là: https://docs.scipy.org/doc/numpy/user/basics.types.html).\n",
"\n",
"Ce qu'il faut en retenir :\n",
"\n",
"* vous pouvez choisir entre `bool`, `int`, `uint` (entier non signé), `float` et `complex` ;\n",
"* ces types ont diverses tailles pour vous permettre d'optimiser la mémoire utilisée ;\n",
"* ces types existent en tant que tels (hors de tableaux)."
]
},
{
"cell_type": "markdown",
"id": "2a765ff9",
"metadata": {},
"source": [
"## organisation de la forme des tableaux"
]
},
{
"cell_type": "markdown",
"id": "e329ff3c",
"metadata": {},
"source": [
"Vous savez désormais que la mémoire qui stocke le tableau est un segment unidimensionnel continu de cases du même type, \n",
"que la taille d'un tableau est fixe \n",
"que la taille des éléments est fixe\n",
"\n",
"Revoici des cases mémoire contiguës en mémoire qui forment un tableau\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"id": "0162b598",
"metadata": {},
"source": [
"Vous avez aussi vu que cette mémoire va être organisée (*indexée*) pour lui donner la forme d'un tableau multi-dimensionnel. Pour l'instant on a vu des matrices donc des tableaux de forme $(d_1, d_2)$. Mais un tableau peut naturellement prendre n'importe quelle dimension.\n",
"\n",
"Prenons un tableau de dimension $(d_1, d_2, d_3, d_4)$. Le segment unidimensionnel continu fera donc $d_1 \\times d_2 \\times d_3 \\times d_4$ cases de long.\n",
"\n",
"Chaque case étant de la taille mémoire suffisante pour stocker le type demandé pour les éléments, par exemple 64 bits.\n",
"\n",
"Dans cette multi-indexation, les deux dernières dimensions sont les *lignes* et les *colonnes* d'une matrice. Dans notre exemple il s'agit de $(d_3, d_4)$. \n",
"\n",
"Ainsi ici $d_2$ serait un nombre de matrices. On a des paquets de $d_2$ matrices. Et $d_1$ serait le nombre de fois où on a ces paquets de matrices.\n",
"\n",
"Ici on aura $d_1$ paquets de $d_2$ matrices de $d_3$ lignes et $d_4$ colonnes.\n",
"\n",
"Ainsi prendre 2 matrices de 3 lignes et 4 colonnes ferait une dimension (2, 3, 4) et ainsi de suite..."
]
},
{
"cell_type": "markdown",
"id": "b6525f4e",
"metadata": {
"tags": [
"level_advanced"
]
},
"source": [
"Pour les avancés, dans l'exemple de l'image en couleur, en encodage RGB, on voit que la dimension de l'image est (530, 800, 3).\n",
"\n",
"C'est à dire que l'image et présentée comme 530 matrices de 800 lignes et 3 colonnes et non pas 3 matrices de 533 lignes et 800 colonnes ! Comme on s'y attendait (peut être)\n",
"\n",
"Pourquoi ? Parce qu'en fait une image est plutôt vue comme une unique matrice où chaque élément (donc chaque pixel de l'image) a trois valeurs: une pour chacune des couleurs primaireset qu'il est préférable de rapprocher les 3 valeurs RGB de chaque pixel pour ne pas ralentir les calculs."
]
},
{
"cell_type": "markdown",
"id": "62b93eb0",
"metadata": {},
"source": [
"Maintenant créons un segment de, par exemple, 30 éléments. Et ne donnons pas de forme, juste la taille. On en profite pour réutiliser la fonction qui fait des tableaux de 1 (la bien-nommée `np.ones`, heu non y'a pas `np.twos` ... `np.threes`)."
]
},
{
"cell_type": "markdown",
"id": "4b751b5b",
"metadata": {
"tags": [
"level_intermediate"
]
},
"source": [
"Pour les avancés. Pourquoi avoir une fonction dédiée aux tableaux de 1 ?\n",
"\n",
"Parce que cela vous permet de créer très rapidement un tableau où tous les éléments ont la même valeur, il suffit de multiplier un tableau de 1 de la bonne forme par votre valeur, on y reviendra ... mais vous pouvez déjà essayer `np.ones(shape=(30,))*np.pi`, oh les 30 beaux $\\pi$ !"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "72d31677",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,\n",
" 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"seg = np.ones(shape=(30,)) # ou shape=30 et il comprend\n",
"seg"
]
},
{
"cell_type": "markdown",
"id": "19eb30af",
"metadata": {},
"source": [
"Quel est le type des éléments ? Une idée ? En bien si vous n'indiquez pas le type des éléments à ce genre de fonctions (comme `np.zeros`, `np.empty`, `np.ones`), elles prennent par défaut le type flottants sur 64 bits. Nous le vérifions:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "01f89a09",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('float64')"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"seg.dtype"
]
},
{
"cell_type": "markdown",
"id": "f8d21933",
"metadata": {},
"source": [
"Donc nous voici avec un tableau dont la taille initiale est la suivante:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "4a3248d6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(30,)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"seg.shape"
]
},
{
"cell_type": "markdown",
"id": "c89a6b9e",
"metadata": {},
"source": [
"Et dont la dimension est la suivante:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "d2e7a49f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"seg.ndim"
]
},
{
"cell_type": "markdown",
"id": "748ae601",
"metadata": {},
"source": [
"Disons que cette forme est celle d'un vecteur *ligne*. Dans ce cas on n'a donc besoin que d'un seul index pour parcourir ce tableau (si on voulait le parcourir). On serait dans ce cas (où $o$ désigne l'offset par rapport au début de la mémoire du tableau; du coup bien sûr ici l'offset se confond avec l'indice)\n",
"\n",
"
\n",
"\n",
"$\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;$ vecteur de 30 élements : ${0\\leq i < 30} \\;\\;\\;\\;\\;\\; i = 15 \\longrightarrow o = 15$"
]
},
{
"cell_type": "markdown",
"id": "b0762023",
"metadata": {},
"source": [
"Et si nous voulions que ce tableau de 30 cases prenne une nouvelle forme: on ne veut plus le considérer comme un vecteur ligne mais comme, par exemple, une matrice avec 3 lignes et 10 colonnes ?\n",
"\n",
"On a bien le même nombre d'éléments (30) dans les deux formes, simplement dans la seconde forme, on est en dimension 2. C'est à dire qu'on aura besoin de deux indices (un pour les lignes et un pour les colonnes) pour parcourir notre matrice (si on voulait la parcourir). On serait dans ce cas:\n",
"\n",
"\n",
"
\n",
"\n",
"$\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;$ matrice 3 x 10 : ${0\\leq i < 3,\\ 0 \\leq j < 10} \\;\\;\\;\\;\\;\\; (i=0, j=0) \\longrightarrow o=0$"
]
},
{
"cell_type": "markdown",
"id": "fc3fd86d",
"metadata": {},
"source": [
"Si je suis sur un élément en début d'une ligne, pour passer directement à l'élément en début de la ligne suivante, combien me faudra-t-il *sauter* d'éléments?\n",
"\n",
"i.e. de combien me faudra-t-il me décaler sur mon segment unidimensionnel sous-jacent ?\n",
"\n",
"Oui il faudra \"sauter\" 10 éléments et 10, on le connait ce chiffre ! c'est la valeur de la deuxième dimension de notre forme (le nombre de colonnes).\n",
"\n",
"
\n",
"\n",
"$\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;$ matrice 3 x 10 : ${0\\leq i < 3,\\ 0 \\leq j < 10} \\;\\;\\;\\;\\;\\; (i=i, j=0) \\longrightarrow o=10$"
]
},
{
"cell_type": "markdown",
"id": "7bfb0e1f",
"metadata": {},
"source": [
"Si je voulais passer de cet élément à celui situé 5 cases à sa droite, je dois simplement sauter 5 nouvelles cases\n",
"\n",
"
\n",
" \n",
"$\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;\\;$ matrice 3 x 10 : ${0\\leq i < 3,\\ 0 \\leq j < 10} \\;\\;\\;\\;\\;\\; (i=1, j=5) \\longrightarrow o=15$"
]
},
{
"cell_type": "markdown",
"id": "41167c53",
"metadata": {},
"source": [
"Et donc la dernière colonne de la dernière ligne se trouve logiquement à la fin de la mémoire \n",
"\n",
"\n",
"