diff --git a/_doc/articles/2025/2025-09-03-ensae.rst b/_doc/articles/2025/2025-09-03-ensae.rst index 786dacd..4840c8c 100644 --- a/_doc/articles/2025/2025-09-03-ensae.rst +++ b/_doc/articles/2025/2025-09-03-ensae.rst @@ -1,5 +1,5 @@ -2025-09-03 : ENSAE -================== +2025-09-03 : ENSAE, Introduction et Attendus +============================================ **Objectif** diff --git a/_doc/articles/2025/2025-11-31-route2025.rst b/_doc/articles/2025/2025-11-31-route2025.rst index b8c2222..43649ea 100644 --- a/_doc/articles/2025/2025-11-31-route2025.rst +++ b/_doc/articles/2025/2025-11-31-route2025.rst @@ -49,6 +49,45 @@ Séance 3 * numpy, broadcasting * implémentation d'un chi-deux sans boucle +* comment implémenter la fonction `repeat_interleave + `_ + avec :epkg:`numpy` et sans boucle ? + En particulier cet exemple ``torch.repeat_interleave(y, torch.tensor([1, 2]), dim=0)`` + +Un problème... que fait la fonction suivante ? + +.. code-block:: python + + def reshape_keep0(arr, new_shape): + orig_shape = arr.shape + final_shape = [] + + for i, dim in enumerate(new_shape): + if dim == 0: + final_shape.append(orig_shape[i]) # garder dimension originale + else: + final_shape.append(dim) + return arr.reshape(tuple(final_shape)) + +Comment construire une fonction qui retourne l'argument ``new_shape`` +quand on connaît les dimensions de départ et d'arrivée ? +La fonction doit valider les exemples suivants, +chaque dimension sous forme de chaîne de caractères peut prendre n'importe +quelle valeur. + +.. code-block:: python + + self.assertEqual((0, 1024, -1), align(("d1", 4, 256, "d2"), ("d1", 1024, "d2"))) + self.assertEqual((0, 0, 1024), align(("d1", "d2", 4, 256), ("d1", "d2", 1024))) + self.assertEqual((6, -1), align((2, 3, "d1"), ("a", "d1"))) + self.assertEqual((6, -1), align((2, 3, "d1"), (6, "d1"))) + self.assertEqual((-1, 12, 196, 64), align(("d1", 196, 64), ("d2", 12, 196, 64))) + self.assertEqual((-1, 196, 64), align(("d1", 196, 64), ("d2", 196, 64))) + self.assertEqual((32, 196, 64), align((32, 196, 64), (32, 196, 64))) + self.assertEqual((4, 8, 196, 64), align((32, 196, 64), (4, 8, 196, 64))) + self.assertEqual((32, 196, 64), align((4, 8, 196, 64), (32, 196, 64))) + self.assertEqual((0, 196, 64), align(("d1", 196, 64), ("d1", 196, 64))) + self.assertEqual((0, 196, 2, 32), align(("d1", 196, 64), ("d1", 196, 2, 32))) Séance 4 ++++++++ diff --git a/_doc/practice/years/2025/index.rst b/_doc/practice/years/2025/index.rst index 5ef3eca..0a22147 100644 --- a/_doc/practice/years/2025/index.rst +++ b/_doc/practice/years/2025/index.rst @@ -1,9 +1,11 @@ .. _l-notebook-2025: -2025 -==== +2025 : notebooks créés en séances +================================= .. toctree:: :maxdepth: 1 seance1_point2d + seance4_algo + seance5_algo2 diff --git a/_doc/practice/years/2025/seance4_algo.ipynb b/_doc/practice/years/2025/seance4_algo.ipynb new file mode 100644 index 0000000..bbe32af --- /dev/null +++ b/_doc/practice/years/2025/seance4_algo.ipynb @@ -0,0 +1,294 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Algorithmes\n", + "\n", + "## Voyageur de commerce" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.90080623, 0.2350022 ],\n", + " [0.56755441, 0.54858335],\n", + " [0.60316886, 0.99559521],\n", + " [0.87287745, 0.22318813],\n", + " [0.21085165, 0.0701609 ]])" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "villes = np.random.rand(20, 2)\n", + "villes[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1, 1, figsize=(3, 3))\n", + "indices = list(range(-1, villes.shape[0]))\n", + "ax.plot(villes[indices, 0], villes[indices, 1], \"o-\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def distance(v1, v2): # v1= np.array([0, 1]), v2= ....\n", + " return ((v1 - v2) ** 2).sum() ** 0.5\n", + "\n", + "\n", + "def plus_proche_non_visitee(villes, chemin):\n", + " depart = chemin[-1]\n", + " dmin, imin = None, None\n", + " for i in range(villes.shape[0]):\n", + " if i not in chemin:\n", + " d = distance(villes[depart], villes[i])\n", + " if dmin is None or d < dmin:\n", + " dmin, imin = d, i\n", + " return imin\n", + "\n", + "\n", + "def algo_proche_en_proche(villes):\n", + " chemin = [0]\n", + " while len(chemin) < villes.shape[0]:\n", + " # trouver la ville la plus proche non visitée de la dernière\n", + " # ville visitée et l'ajouter au chemin\n", + " inext = plus_proche_non_visitee(villes, chemin)\n", + " chemin.append(inext)\n", + " return chemin\n", + "\n", + "\n", + "chemin = algo_proche_en_proche(villes)\n", + "indices = chemin + chemin[:1]\n", + "fig, ax = plt.subplots(1, 1, figsize=(3, 3))\n", + "ax.plot(villes[indices, 0], villes[indices, 1], \"o-\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mieux -1 3 -0.15191965099971733 [0, 3, 14, 19] []\n", + "mieux -1 11 -0.5172511323315206 [19, 14, 3, 0, 16, 6, 10, 17, 15, 11, 18, 2] []\n", + "mieux 11 13 -0.0513745444570991 [1, 12] [12, 1]\n", + "mieux 11 17 -0.0044994455150375035 [12, 1, 7, 9, 4, 5] [5, 4, 9, 7, 1, 12]\n", + "mieux 15 17 -0.03444152981270798 [1, 12] [12, 1]\n", + "mieux 11 13 -0.12384307859548493 [5, 4] [4, 5]\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def elimine_croisements(villes, chemin):\n", + " C = chemin\n", + " while True:\n", + " mieux = 0\n", + " for i in range(-1, villes.shape[0]):\n", + " for j in range(i + 2, villes.shape[0] - 1):\n", + " delta = (\n", + " -distance(villes[C[i]], villes[C[i + 1]])\n", + " - distance(villes[C[j]], villes[C[j + 1]])\n", + " + distance(villes[C[i]], villes[C[j]])\n", + " + distance(villes[C[i + 1]], villes[C[j + 1]])\n", + " )\n", + " if delta < 0:\n", + " mieux += 1\n", + " print(\"mieux\", i, j, delta, chemin[i + 1 : j + 1], chemin[j:i:-1])\n", + " # c'est mieux... on retourne les villes du chemin\n", + " # entre i+1 et j inclus\n", + " if i >= 0:\n", + " chemin[i + 1 : j + 1] = chemin[j:i:-1]\n", + " else:\n", + " chemin[i + 1 : j + 1] = chemin[j::-1]\n", + " if mieux == 0:\n", + " break\n", + "\n", + "\n", + "elimine_croisements(villes, chemin)\n", + "fig, ax = plt.subplots(1, 1, figsize=(3, 3))\n", + "indices = chemin + chemin[:1]\n", + "ax.plot(villes[indices, 0], villes[indices, 1], \"o-\")\n", + "ax.plot(villes[chemin[:1], 0], villes[chemin[:1], 1], \"or\")\n", + "ax.plot(villes[chemin[-1:], 0], villes[chemin[-1:], 1], \"og\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Distance d'édition" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(np.int64(1), np.int64(1)), (np.int64(2), np.int64(1)), (np.int64(3), np.int64(2)), (np.int64(4), np.int64(3)), (np.int64(4), np.int64(4)), (5, 5)]\n", + "[('E', 'E'), ('N', 'E'), ('S', 'S'), ('A', 'A'), ('A', 'N'), ('E', 'E')]\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[0., 1., 2., 3., 4., 5.],\n", + " [1., 0., 1., 2., 3., 4.],\n", + " [2., 1., 1., 2., 2., 3.],\n", + " [3., 2., 1., 2., 3., 3.],\n", + " [4., 3., 2., 1., 2., 3.],\n", + " [5., 4., 3., 2., 2., 2.]])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def distance_edition(m1, m2):\n", + " cout = np.empty((len(m1) + 1, len(m2) + 1))\n", + " predi = np.empty((len(m1) + 1, len(m2) + 1), dtype=np.int64)\n", + " predj = np.empty((len(m1) + 1, len(m2) + 1), dtype=np.int64)\n", + " cout[:, 0] = np.arange(len(m1) + 1)\n", + " cout[0, :] = np.arange(len(m2) + 1)\n", + " predi[:, 0] = np.arange(len(m1) + 1) - 1\n", + " predj[:, 0] = 0\n", + " predi[0, :] = 0\n", + " predj[0, :] = np.arange(len(m2) + 1) - 1\n", + " for i in range(1, len(m1) + 1):\n", + " for j in range(1, len(m2) + 1):\n", + " c_sup = cout[i - 1, j] + 1\n", + " c_ins = cout[i, j - 1] + 1\n", + " c_cmp = cout[i - 1, j - 1] + (1 if m1[i - 1] != m2[j - 1] else 0)\n", + " if c_cmp <= min(c_sup, c_ins):\n", + " cout[i, j], predi[i, j], predj[i, j] = c_cmp, i - 1, j - 1\n", + " elif c_sup <= c_ins:\n", + " cout[i, j], predi[i, j], predj[i, j] = c_sup, i - 1, j\n", + " else:\n", + " cout[i, j], predi[i, j], predj[i, j] = c_ins, i, j - 1\n", + " # alignement\n", + " alignement = [(len(m1), len(m2))]\n", + " while min(alignement[-1]) >= 0:\n", + " i, j = alignement[-1]\n", + " i, j = predi[i, j], predj[i, j]\n", + " alignement.append((i, j))\n", + " alignement = alignement[::-1][2:]\n", + " lettres = [(m1[i - 1], m2[j - 1]) for i, j in alignement]\n", + " return cout, alignement, lettres\n", + "\n", + "\n", + "cout, alignement, lettres = distance_edition(\"ENSAE\", \"ESANE\")\n", + "print(alignement)\n", + "print(lettres)\n", + "cout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/_doc/practice/years/2025/seance5_algo2.ipynb b/_doc/practice/years/2025/seance5_algo2.ipynb new file mode 100644 index 0000000..7e7d170 --- /dev/null +++ b/_doc/practice/years/2025/seance5_algo2.ipynb @@ -0,0 +1,990 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Algorithmes\n", + "\n", + "## Mesurer le temps" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, RuntimeError('stop')]\n" + ] + } + ], + "source": [ + "def fonction1():\n", + " raise RuntimeError(\"stop\")\n", + "\n", + "\n", + "def fonction2():\n", + " return fonction1()\n", + "\n", + "\n", + "def fonction3():\n", + " return fonction2()\n", + "\n", + "\n", + "try:\n", + " fonction3()\n", + "except Exception as e:\n", + " print([type(e), e])" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "list 0.00920867919921875\n" + ] + } + ], + "source": [ + "def recherche_list(ensemble: list, element) -> bool:\n", + " return element in ensemble\n", + "\n", + "\n", + "def recherche_set(ensemble: set, element) -> bool:\n", + " return element in ensemble\n", + "\n", + "\n", + "def recherche_dict(ensemble: dict, element) -> bool:\n", + " return element in ensemble\n", + "\n", + "\n", + "N = 10000\n", + "list_entier = list(range(N))\n", + "set_entier = set(range(N))\n", + "dict_entier = {k: 0 for k in range(N)}\n", + "\n", + "T = 100\n", + "import time\n", + "\n", + "begin = time.time()\n", + "for i in range(T):\n", + " recherche_list(list_entier, 9000)\n", + "duree = time.time() - begin\n", + "print(\"list\", duree)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "list 0.6168732643127441\n", + "set 0.0010602474212646484\n", + "dict 0.0015003681182861328\n" + ] + } + ], + "source": [ + "T = 10000\n", + "el = 9999\n", + "begin = time.time()\n", + "for i in range(T):\n", + " recherche_list(list_entier, el)\n", + "duree = time.time() - begin\n", + "print(\"list\", duree)\n", + "\n", + "begin = time.time()\n", + "for i in range(T):\n", + " recherche_set(set_entier, el)\n", + "duree = time.time() - begin\n", + "print(\"set\", duree)\n", + "\n", + "begin = time.time()\n", + "for i in range(T):\n", + " recherche_dict(dict_entier, el)\n", + "duree = time.time() - begin\n", + "print(\"dict\", duree)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b'Bonjour le mondesd\\xe3\\x83\\x8a\\xe3\\x83\\xab\\xe3\\x83\\x88'\n", + "9b158061cd\n" + ] + } + ], + "source": [ + "import hashlib\n", + "\n", + "# Texte à hacher\n", + "texte = \"Bonjour le mondesdナルト\".encode(\"utf-8\")\n", + "print(texte)\n", + "\n", + "# Création du hash SHA-256\n", + "hash_obj = hashlib.sha256(texte)\n", + "hash_hex = hash_obj.hexdigest()[:10]\n", + "\n", + "print(hash_hex)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Profiling" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def f():\n", + " for i in range(T):\n", + " recherche_list(list_entier, el)\n", + " recherche_set(set_entier, el)\n", + " recherche_dict(dict_entier, el)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " _ ._ __/__ _ _ _ _ _/_ Recorded: 22:16:49 Samples: 643\n", + " /_//_/// /_\\ / //_// / //_'/ // Duration: 0.664 CPU time: 0.669\n", + "/ _/ v5.1.1\n", + "\n", + "Profile at /tmp/ipykernel_231901/1337574655.py:4\n", + "\n", + "0.663 ZMQInteractiveShell.run_ast_nodes IPython/core/interactiveshell.py:3418\n", + "`- 0.662 /tmp/ipykernel_231901/1337574655.py:1\n", + " `- 0.662 f /tmp/ipykernel_231901/2115577803.py:1\n", + " |- 0.648 recherche_list /tmp/ipykernel_231901/3550779215.py:1\n", + " `- 0.012 [self] /tmp/ipykernel_231901/2115577803.py\n", + "\n", + "\n" + ] + } + ], + "source": [ + "from pyinstrument import Profiler\n", + "\n", + "profiler = Profiler()\n", + "profiler.start()\n", + "\n", + "# Code à profiler\n", + "f()\n", + "\n", + "profiler.stop()\n", + "print(profiler.output_text())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " " + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 30757 function calls (30742 primitive calls) in 0.667 seconds\n", + "\n", + " Ordered by: internal time\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 10000 0.638 0.000 0.638 0.000 3550779215.py:1(recherche_list)\n", + " 1 0.007 0.007 0.459 0.459 2115577803.py:1(f)\n", + " 6/4 0.007 0.001 0.007 0.002 events.py:86(_run)\n", + " 2/1 0.005 0.003 0.459 0.459 :1()\n", + " 3/1 0.003 0.001 0.000 0.000 selectors.py:451(select)\n", + " 10000 0.002 0.000 0.002 0.000 3550779215.py:4(recherche_set)\n", + " 10000 0.002 0.000 0.002 0.000 3550779215.py:7(recherche_dict)\n", + " 14 0.001 0.000 0.001 0.000 socket.py:626(send)\n", + " 1 0.000 0.000 0.020 0.020 history.py:833(_writeout_input_cache)\n", + " 3/1 0.000 0.000 0.000 0.000 {method 'poll' of 'select.epoll' objects}\n", + " 2 0.000 0.000 0.006 0.003 socket.py:703(send_multipart)\n", + " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", + " 1 0.000 0.000 0.027 0.027 history.py:55(only_when_enabled)\n", + " 2 0.000 0.000 0.000 0.000 {method 'recv' of '_socket.socket' objects}\n", + " 2 0.000 0.000 0.000 0.000 {method '__exit__' of 'sqlite3.Connection' objects}\n", + " 2 0.000 0.000 0.000 0.000 socket.py:774(recv_multipart)\n", + " 4 0.000 0.000 0.171 0.043 base_events.py:1922(_run_once)\n", + " 5 0.000 0.000 0.000 0.000 attrsettr.py:66(_get_attr_opt)\n", + " 72 0.000 0.000 0.000 0.000 enum.py:1538(_get_value)\n", + " 2/1 0.000 0.000 0.650 0.650 {built-in method builtins.exec}\n", + " 1 0.000 0.000 0.000 0.000 {method 'execute' of 'sqlite3.Connection' objects}\n", + " 152/148 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}\n", + " 16 0.000 0.000 0.000 0.000 enum.py:1545(__or__)\n", + " 1 0.000 0.000 0.000 0.000 poll.py:80(poll)\n", + " 5 0.000 0.000 0.000 0.000 attrsettr.py:43(__getattr__)\n", + " 2/1 0.000 0.000 0.027 0.027 decorator.py:229(fun)\n", + " 31 0.000 0.000 0.000 0.000 enum.py:720(__call__)\n", + " 1 0.000 0.000 0.000 0.000 {method 'send' of '_socket.socket' objects}\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:3133(_bind)\n", + " 8 0.000 0.000 0.000 0.000 enum.py:1556(__and__)\n", + " 6/4 0.000 0.000 0.001 0.000 {method 'run' of '_contextvars.Context' objects}\n", + " 1 0.000 0.000 0.000 0.000 kernelbase.py:302(poll_control_queue)\n", + " 31 0.000 0.000 0.000 0.000 enum.py:1123(__new__)\n", + " 6 0.000 0.000 0.000 0.000 typing.py:392(inner)\n", + " 2 0.000 0.000 0.006 0.003 iostream.py:278(_really_send)\n", + " 1 0.000 0.000 0.020 0.020 history.py:845(writeout_cache)\n", + " 2 0.000 0.000 0.007 0.003 zmqstream.py:583(_handle_events)\n", + " 1 0.000 0.000 0.000 0.000 selector_events.py:129(_read_from_self)\n", + " 1 0.000 0.000 0.000 0.000 traitlets.py:1527(_notify_observers)\n", + " 8 0.000 0.000 0.000 0.000 traitlets.py:676(__get__)\n", + " 3 0.000 0.000 0.000 0.000 zmqstream.py:686(_update_handler)\n", + " 3 0.000 0.000 0.000 0.000 ioloop.py:742(_run_callback)\n", + " 2 0.000 0.000 0.000 0.000 typing.py:1492(__subclasscheck__)\n", + " 1 0.000 0.000 0.000 0.000 decorator.py:199(fix)\n", + " 3 0.000 0.000 0.000 0.000 zmqstream.py:663(_rebuild_io_state)\n", + " 2 0.000 0.000 0.006 0.003 iostream.py:157(_handle_event)\n", + " 2 0.000 0.000 0.006 0.003 zmqstream.py:556(_run_callback)\n", + " 1 0.000 0.000 0.000 0.000 kernelbase.py:324(_flush)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:3631(set)\n", + " 4 0.000 0.000 0.000 0.000 queue.py:97(empty)\n", + " 7 0.000 0.000 0.000 0.000 base_events.py:738(time)\n", + " 2 0.000 0.000 0.006 0.003 zmqstream.py:624(_handle_recv)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:225(get)\n", + " 8 0.000 0.000 0.000 0.000 traitlets.py:629(get)\n", + " 3 0.000 0.000 0.000 0.000 base_events.py:818(_call_soon)\n", + " 25 0.000 0.000 0.000 0.000 {built-in method builtins.len}\n", + " 1 0.000 0.000 0.000 0.000 zmqstream.py:427(flush)\n", + " 4 0.000 0.000 0.000 0.000 typing.py:1285(__hash__)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:708(__set__)\n", + " 1 0.000 0.000 0.000 0.000 asyncio.py:225(add_callback)\n", + " 5 0.000 0.000 0.000 0.000 selector_events.py:750(_process_events)\n", + " 2 0.000 0.000 0.006 0.003 iostream.py:276()\n", + " 1 0.000 0.000 0.000 0.000 _base.py:537(set_result)\n", + " 1 0.000 0.000 0.000 0.000 iostream.py:718(_rotate_buffers)\n", + " 1 0.000 0.000 0.000 0.000 iostream.py:616(_flush)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:689(set)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:718(_validate)\n", + " 5 0.000 0.000 0.000 0.000 :1390(_handle_fromlist)\n", + " 1 0.000 0.000 0.000 0.000 threading.py:311(_acquire_restore)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2949(apply_defaults)\n", + " 2 0.000 0.000 0.000 0.000 typing.py:1221(__instancecheck__)\n", + " 5 0.000 0.000 0.000 0.000 {built-in method builtins.getattr}\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:3272(bind)\n", + " 3 0.000 0.000 0.000 0.000 threading.py:299(__enter__)\n", + " 2 0.000 0.000 0.000 0.000 base_events.py:1907(_add_callback)\n", + " 10 0.000 0.000 0.000 0.000 {built-in method builtins.hasattr}\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:3474(validate)\n", + " 1 0.000 0.000 0.000 0.000 iostream.py:710(_flush_buffers)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:209(put_nowait)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:3624(validate_elements)\n", + " 7 0.000 0.000 0.000 0.000 {built-in method time.monotonic}\n", + " 1 0.000 0.000 0.000 0.000 queues.py:186(put)\n", + " 3 0.000 0.000 0.000 0.000 events.py:36(__init__)\n", + " 1 0.000 0.000 0.000 0.000 zmqstream.py:468(update_flag)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:727(_cross_validate)\n", + " 7 0.000 0.000 0.000 0.000 {built-in method builtins.max}\n", + " 3 0.000 0.000 0.000 0.000 threading.py:302(__exit__)\n", + " 1 0.000 0.000 0.000 0.000 traitlets.py:1512(_notify_trait)\n", + " 10 0.000 0.000 0.000 0.000 {method 'popleft' of 'collections.deque' objects}\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2896(args)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2919(kwargs)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:2304(validate)\n", + " 2 0.000 0.000 0.000 0.000 base_events.py:789(call_soon)\n", + " 8 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.lock' objects}\n", + " 1 0.000 0.000 0.000 0.000 traitlets.py:1523(notify_change)\n", + " 9 0.000 0.000 0.000 0.000 {method 'append' of 'collections.deque' objects}\n", + " 2 0.000 0.000 0.000 0.000 iostream.py:213(_is_master_process)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:256(get_nowait)\n", + " 1 0.000 0.000 0.006 0.006 asyncio.py:200(_handle_events)\n", + " 1 0.000 0.000 0.000 0.000 futures.py:396(_call_set_state)\n", + " 1 0.000 0.000 0.000 0.000 threading.py:424(notify_all)\n", + " 2 0.000 0.000 0.000 0.000 queues.py:322(_consume_expired)\n", + " 1 0.000 0.000 0.000 0.000 threading.py:627(clear)\n", + " 28 0.000 0.000 0.000 0.000 typing.py:2187(cast)\n", + " 2 0.000 0.000 0.000 0.000 {built-in method builtins.issubclass}\n", + " 4 0.000 0.000 0.000 0.000 zmqstream.py:542(sending)\n", + " 5 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects}\n", + " 2 0.000 0.000 0.000 0.000 :121(__subclasscheck__)\n", + " 6 0.000 0.000 0.000 0.000 {built-in method builtins.next}\n", + " 2 0.000 0.000 0.000 0.000 {built-in method _abc._abc_subclasscheck}\n", + " 1 0.000 0.000 0.000 0.000 base_events.py:842(call_soon_threadsafe)\n", + " 6 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}\n", + " 2 0.000 0.000 0.000 0.000 {method 'set_result' of '_asyncio.Future' objects}\n", + " 2 0.000 0.000 0.000 0.000 {built-in method builtins.min}\n", + " 3 0.000 0.000 0.000 0.000 {method 'acquire' of '_thread.lock' objects}\n", + " 2 0.000 0.000 0.000 0.000 iostream.py:216(_check_mp_mode)\n", + " 1 0.000 0.000 0.000 0.000 history.py:839(_writeout_output_cache)\n", + " 1 0.000 0.000 0.000 0.000 selector_events.py:141(_write_to_self)\n", + " 2 0.000 0.000 0.000 0.000 {built-in method math.ceil}\n", + " 1 0.000 0.000 0.000 0.000 concurrent.py:182(future_set_result_unless_cancelled)\n", + " 1 0.000 0.000 0.000 0.000 _base.py:337(_invoke_callbacks)\n", + " 3 0.000 0.000 0.000 0.000 {method 'items' of 'mappingproxy' objects}\n", + " 1 0.000 0.000 0.000 0.000 queues.py:317(__put_internal)\n", + " 2 0.000 0.000 0.000 0.000 selectors.py:275(_key_from_fd)\n", + " 4 0.000 0.000 0.000 0.000 queue.py:209(_qsize)\n", + " 1 0.000 0.000 0.000 0.000 threading.py:308(_release_save)\n", + " 2 0.000 0.000 0.000 0.000 {built-in method _contextvars.copy_context}\n", + " 1 0.000 0.000 0.000 0.000 {built-in method _asyncio.get_running_loop}\n", + " 1 0.000 0.000 0.000 0.000 threading.py:394(notify)\n", + " 2 0.000 0.000 0.000 0.000 {built-in method posix.getpid}\n", + " 4 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects}\n", + " 1 0.000 0.000 0.000 0.000 {built-in method _heapq.heappop}\n", + " 1 0.000 0.000 0.000 0.000 {method 'values' of 'mappingproxy' objects}\n", + " 4 0.000 0.000 0.000 0.000 {built-in method builtins.hash}\n", + " 1 0.000 0.000 0.000 0.000 {method '__enter__' of '_thread.RLock' objects}\n", + " 10 0.000 0.000 0.000 0.000 inspect.py:2808(kind)\n", + " 1 0.000 0.000 0.000 0.000 {built-in method _thread.allocate_lock}\n", + " 1 0.000 0.000 0.000 0.000 unix_events.py:81(_process_self_data)\n", + " 2 0.000 0.000 0.000 0.000 traitlets.py:3486(validate_elements)\n", + " 2 0.000 0.000 0.000 0.000 {method '__enter__' of '_thread.lock' objects}\n", + " 5 0.000 0.000 0.000 0.000 zmqstream.py:538(receiving)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:173(qsize)\n", + " 1 0.000 0.000 0.000 0.000 poll.py:31(register)\n", + " 2 0.000 0.000 0.000 0.000 {built-in method builtins.iter}\n", + " 2 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.RLock' objects}\n", + " 1 0.000 0.000 0.000 0.000 zmqstream.py:694()\n", + " 3 0.000 0.000 0.000 0.000 base_events.py:543(_check_closed)\n", + " 5 0.000 0.000 0.000 0.000 base_events.py:2017(get_debug)\n", + " 2 0.000 0.000 0.000 0.000 iostream.py:255(closed)\n", + " 4 0.000 0.000 0.000 0.000 inspect.py:2796(name)\n", + " 1 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects}\n", + " 2 0.000 0.000 0.000 0.000 {method 'cancelled' of '_asyncio.Future' objects}\n", + " 1 0.000 0.000 0.000 0.000 queues.py:309(_get)\n", + " 1 0.000 0.000 0.000 0.000 zmqstream.py:659(_check_closed)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:312(_put)\n", + " 4 0.000 0.000 0.000 0.000 inspect.py:3089(parameters)\n", + " 2 0.000 0.000 0.000 0.000 {method 'extend' of 'list' objects}\n", + " 1 0.000 0.000 0.000 0.000 threading.py:314(_is_owned)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:177(empty)\n", + " 1 0.000 0.000 0.000 0.000 {method '_is_owned' of '_thread.RLock' objects}\n", + " 1 0.000 0.000 0.000 0.000 {method 'done' of '_asyncio.Future' objects}\n", + " 1 0.000 0.000 0.000 0.000 base_events.py:724(is_closed)\n", + " 1 0.000 0.000 0.000 0.000 queues.py:59(_set_timeout)\n", + " 1 0.000 0.000 0.000 0.000 {method 'release' of '_thread.lock' objects}\n", + " 1 0.000 0.000 0.000 0.000 locks.py:224(clear)\n", + " 1 0.000 0.000 0.000 0.000 inspect.py:2888(__init__)" + ] + } + ], + "source": [ + "%prun f()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimisation d'un programme" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([[0.02609378, 0.47304915],\n", + " [0.11827469, 0.76657083],\n", + " [0.827706 , 0.26337121],\n", + " [0.56057621, 0.53610594],\n", + " [0.22134542, 0.73108227]]),\n", + " [7, 19, 0, 9, 18, 8, 17, 15, 5, 14, 2, 13, 11, 12, 6, 16, 10, 1, 4, 3])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "def distance(v1, v2): # v1= np.array([0, 1]), v2= ....\n", + " return ((v1 - v2) ** 2).sum() ** 0.5\n", + " # return ((v1[0] - v2[0]) ** 2 + (v1[1] - v2[1]) ** 2) ** 0.5\n", + "\n", + "\n", + "def plus_proche_non_visitee(villes, chemin):\n", + " depart = chemin[-1]\n", + " dmin, imin = None, None\n", + " for i in range(villes.shape[0]):\n", + " if i not in chemin:\n", + " d = distance(villes[depart], villes[i])\n", + " if dmin is None or d < dmin:\n", + " dmin, imin = d, i\n", + " return imin\n", + "\n", + "\n", + "def algo_proche_en_proche(villes):\n", + " chemin = [0]\n", + " while len(chemin) < villes.shape[0]:\n", + " # trouver la ville la plus proche non visitée de la dernière\n", + " # ville visitée et l'ajouter au chemin\n", + " inext = plus_proche_non_visitee(villes, chemin)\n", + " chemin.append(inext)\n", + " return chemin\n", + "\n", + "\n", + "def elimine_croisements(villes, chemin):\n", + " C = chemin\n", + " while True:\n", + " mieux = 0\n", + " for i in range(-1, villes.shape[0]):\n", + " for j in range(i + 2, villes.shape[0] - 1):\n", + " delta = (\n", + " -distance(villes[C[i]], villes[C[i + 1]])\n", + " - distance(villes[C[j]], villes[C[j + 1]])\n", + " + distance(villes[C[i]], villes[C[j]])\n", + " + distance(villes[C[i + 1]], villes[C[j + 1]])\n", + " )\n", + " if delta < 0:\n", + " mieux += 1\n", + " if i >= 0:\n", + " chemin[i + 1 : j + 1] = chemin[j:i:-1]\n", + " else:\n", + " chemin[i + 1 : j + 1] = chemin[j::-1]\n", + " if mieux == 0:\n", + " break\n", + "\n", + "\n", + "villes = np.random.rand(20, 2)\n", + "chemin = algo_proche_en_proche(villes)\n", + "elimine_croisements(villes, chemin)\n", + "villes[:5], chemin" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "t= 0 N= 100\n", + "[75, 51, 15, 20, 73, 40, 82, 38, 59, 94, 36, 54, 88, 26, 97, 44, 81, 13, 96, 99, 28, 9, 14, 78, 46, 85, 83, 22, 93, 52, 2, 56, 42, 27, 49, 25, 62, 39, 5, 92, 34, 21, 66, 16, 30, 37, 70, 57, 76, 86, 63, 33, 19, 58, 43, 23, 65, 3, 45, 72, 77, 0, 60, 32, 89, 4, 61, 71, 84, 79, 18, 87, 67, 31, 24, 74, 50, 10, 91, 68, 98, 1, 64, 41, 48, 95, 80, 69, 29, 55, 12, 47, 6, 11, 35, 90, 17, 7, 53, 8]\n" + ] + } + ], + "source": [ + "def problem(N, T):\n", + " for t in range(T):\n", + " print(\"t=\", t, \"N=\", N)\n", + " villes = np.random.rand(N, 2)\n", + " chemin = algo_proche_en_proche(villes)\n", + " elimine_croisements(villes, chemin)\n", + " return chemin\n", + "\n", + "\n", + "print(problem(100, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "import cProfile, pstats, io\n", + "from pstats import SortKey\n", + "pr = cProfile.Profile()\n", + "pr.enable()\n", + "\n", + "problem(10, 5)\n", + "\n", + "pr.disable()\n", + "s = io.StringIO()\n", + "sortby = SortKey.CUMULATIVE\n", + "ps = pstats.Stats(pr, stream=s).sort_stats(sortby)\n", + "ps.print_stats()\n", + "print(s.getvalue().replace(\"= 0:\n", + " chemin[i + 1 : j + 1] = chemin[j:i:-1]\n", + " else:\n", + " chemin[i + 1 : j + 1] = chemin[j::-1]\n", + " if mieux == 0:\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Préfixes" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'': [''], 'B': ['A', 'CA', ''], 'E': ['E', 'F', 'G'], 'A': ['B', 'BC']}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def casse_liste(liste):\n", + " premiere_lettre = set(mot[:1] for mot in liste)\n", + " res = {}\n", + " for p in premiere_lettre:\n", + " res[p] = [mot[1:] for mot in liste if mot[:1] == p]\n", + " return res\n", + "\n", + "\n", + "liste = [\"AB\", \"ABC\", \"BA\", \"BCA\", \"B\", \"EE\", \"EF\", \"EG\", \"\"]\n", + "casse_liste(liste)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'': {},\n", + " 'B': {'C': {'A': {}}, '': {}, 'A': {}},\n", + " 'E': {'E': {}, 'F': {}, 'G': {}},\n", + " 'A': {'B': {'': {}, 'C': {}}}}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def casse_liste_rec(liste):\n", + " if not liste or liste == [\"\"]:\n", + " return {}\n", + " premiere_lettre = set(mot[:1] for mot in liste)\n", + " res = {}\n", + " for p in premiere_lettre:\n", + " res[p] = casse_liste_rec([mot[1:] for mot in liste if mot[:1] == p])\n", + " return res\n", + "\n", + "\n", + "liste = [\"AB\", \"ABC\", \"BA\", \"BCA\", \"B\", \"EE\", \"EF\", \"EG\", \"\"]\n", + "casse_liste_rec(liste)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'': {},\n", + " 'A': {'B': {'': {}, 'C': {}}},\n", + " 'B': {'': {}, 'A': {}, 'C': {'A': {}}},\n", + " 'E': {'E': {}, 'F': {}, 'G': {}}}\n" + ] + } + ], + "source": [ + "import pprint\n", + "\n", + "pprint.pprint(casse_liste_rec(liste))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['', 'BCA', 'B', 'BA', 'EE', 'EF', 'EG', 'AB', 'ABC']" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def reconstruit_liste(trie, prefixe=\"\"):\n", + " mots = []\n", + " for lettre, sous_trie in trie.items():\n", + " nouveau_prefixe = prefixe + lettre\n", + " if not sous_trie: # Si le sous-trie est vide, c'est la fin d'un mot\n", + " mots.append(nouveau_prefixe)\n", + " else:\n", + " mots.extend(reconstruit_liste(sous_trie, nouveau_prefixe))\n", + " return mots\n", + "\n", + "\n", + "liste = [\"AB\", \"ABC\", \"BA\", \"BCA\", \"B\", \"EE\", \"EF\", \"EG\", \"\"]\n", + "trie = casse_liste_rec(liste)\n", + "liste_reconstruite = reconstruit_liste(trie)\n", + "liste_reconstruite" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(True, True, False)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def search_trie(trie, mot):\n", + " if not mot:\n", + " return True # Mot vide, considéré comme présent\n", + " if not trie:\n", + " return False # Trie vide, mot absent\n", + " premiere_lettre = mot[0]\n", + " if premiere_lettre not in trie:\n", + " return False\n", + " return search_trie(trie[premiere_lettre], mot[1:])\n", + "\n", + "\n", + "search_trie(trie, \"\"), search_trie(trie, \"BC\"), search_trie(trie, \"Z\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(True, True, False)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def search_trie2(trie, mot):\n", + " current = trie\n", + " for lettre in mot:\n", + " if lettre not in current:\n", + " return False\n", + " current = current[lettre]\n", + " return True\n", + "\n", + "\n", + "search_trie2(trie, \"\"), search_trie2(trie, \"BC\"), search_trie2(trie, \"Z\")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['BCA', 'B', 'BA', 'EE', 'EF', 'EG', 'AB']" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def intersection_tries_naive(trie1, trie2):\n", + " liste = reconstruit_liste(trie1)\n", + " return [mot for mot in liste if search_trie2(trie2, mot)]\n", + "\n", + "\n", + "liste1 = [\"AB\", \"ABC\", \"BA\", \"BCA\", \"B\", \"EE\", \"EF\", \"EG\"]\n", + "trie1 = casse_liste_rec(liste1)\n", + "liste2 = [\"AB\", \"BA\", \"BCA\", \"B\", \"EE\", \"EF\", \"EG\", \"EH\"]\n", + "trie2 = casse_liste_rec(liste2)\n", + "intersection_tries_naive(trie1, trie2)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['BCA', 'B', 'BA', 'EE', 'EF', 'EG']" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def intersection_tries(trie1, trie2, prefixe=\"\"):\n", + " mots = []\n", + " # Parcourir les clés communes aux deux tries\n", + " for lettre in set(trie1.keys()) & set(trie2.keys()):\n", + " nouveau_prefixe = prefixe + lettre\n", + " # Si les deux sous-tries sont vides, c'est un mot commun\n", + " if not trie1[lettre] and not trie2[lettre]:\n", + " mots.append(nouveau_prefixe)\n", + " else:\n", + " # Sinon, continuer récursivement\n", + " mots.extend(\n", + " intersection_tries(trie1[lettre], trie2[lettre], nouveau_prefixe)\n", + " )\n", + " return mots\n", + "\n", + "\n", + "intersection_tries(trie1, trie2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "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.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/_unittests/ut_xrun_doc/test_documentation_examples.py b/_unittests/ut_xrun_doc/test_documentation_examples.py index c7a4a4f..ef8a32b 100644 --- a/_unittests/ut_xrun_doc/test_documentation_examples.py +++ b/_unittests/ut_xrun_doc/test_documentation_examples.py @@ -40,7 +40,7 @@ def run_test(self, fold: str, name: str, verbose=0) -> int: cmds = [sys.executable, "-u", os.path.join(fold, name)] p = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE) res = p.communicate() - out, err = res + _out, err = res st = err.decode("ascii", errors="ignore") if "No such file or directory" in st: raise FileNotFoundError(st) # noqa: B904 diff --git a/_unittests/ut_xrun_doc/test_documentation_notebook.py b/_unittests/ut_xrun_doc/test_documentation_notebook.py index 315f3ed..3ecf8b3 100644 --- a/_unittests/ut_xrun_doc/test_documentation_notebook.py +++ b/_unittests/ut_xrun_doc/test_documentation_notebook.py @@ -74,7 +74,7 @@ def run_test(self, nb_name: str, verbose=0) -> int: cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) res = p.communicate() - out, err = res + _out, err = res st = err.decode("ascii", errors="ignore") if "No such file or directory" in st: raise FileNotFoundError(st) # noqa: B904