Skip to content

Commit e965a7f

Browse files
committed
fix
1 parent 77727b3 commit e965a7f

File tree

2 files changed

+171
-46
lines changed

2 files changed

+171
-46
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,10 @@ jobs:
4444
- name: run tests
4545
run: |
4646
pip install pytest
47-
PYTHONPATH=. UNITTEST_GOING=1 pytest --durations=10 _unittests --ignore-glob=**pygame*.py
47+
PYTHONPATH=. UNITTEST_GOING=1 pytest --durations=10 _unittests --ignore-glob=**pygame*.py --ignore _unittests/ut_xrun_doc/test_documentation_examples.py --ignore _unittests/ut_xrun_doc/test_documentation_notebook.py
48+
49+
- name: run tests examples
50+
run: PYTHONPATH=. UNITTEST_GOING=1 python --durations=10 _unittests/ut_xrun_doc/test_documentation_examples.py
51+
52+
- name: run tests notebooks
53+
run: PYTHONPATH=. UNITTEST_GOING=1 python --durations=10 _unittests/ut_xrun_doc/test_documentation_notebooks.py

_doc/practice/exams/td_note_2025.ipynb

Lines changed: 164 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
"cell_type": "markdown",
1616
"metadata": {},
1717
"source": [
18-
"## Q1"
18+
"## Q1 - Implémenter une fonction qui calcule la distance entre deux matrices"
1919
]
2020
},
2121
{
2222
"cell_type": "code",
23-
"execution_count": 3,
23+
"execution_count": 1,
2424
"metadata": {},
2525
"outputs": [
2626
{
@@ -29,7 +29,7 @@
2929
"np.int64(45)"
3030
]
3131
},
32-
"execution_count": 3,
32+
"execution_count": 1,
3333
"metadata": {},
3434
"output_type": "execute_result"
3535
}
@@ -51,12 +51,12 @@
5151
"cell_type": "markdown",
5252
"metadata": {},
5353
"source": [
54-
"## Q2"
54+
"## Q2 - Implémenter une fonction qui retourne les p ermutations des n premiers entiers"
5555
]
5656
},
5757
{
5858
"cell_type": "code",
59-
"execution_count": 6,
59+
"execution_count": 2,
6060
"metadata": {},
6161
"outputs": [
6262
{
@@ -88,7 +88,7 @@
8888
" (3, 2, 1, 0)]"
8989
]
9090
},
91-
"execution_count": 6,
91+
"execution_count": 2,
9292
"metadata": {},
9393
"output_type": "execute_result"
9494
}
@@ -108,12 +108,12 @@
108108
"cell_type": "markdown",
109109
"metadata": {},
110110
"source": [
111-
"## Q3, Q4"
111+
"## Q3, Q4 - Implémenter une fonction qui p ermute les colonnes d'une matrice."
112112
]
113113
},
114114
{
115115
"cell_type": "code",
116-
"execution_count": 23,
116+
"execution_count": 3,
117117
"metadata": {},
118118
"outputs": [
119119
{
@@ -124,7 +124,7 @@
124124
" [ 8, 7]])"
125125
]
126126
},
127-
"execution_count": 23,
127+
"execution_count": 3,
128128
"metadata": {},
129129
"output_type": "execute_result"
130130
}
@@ -145,12 +145,12 @@
145145
"cell_type": "markdown",
146146
"metadata": {},
147147
"source": [
148-
"## Q5"
148+
"## Q5 - Ecrire une fonctionne qui retourne les deux p ermutations ligne/colonne qui minimise la distance entre les deux matrices, en déduire la case qui a changé."
149149
]
150150
},
151151
{
152152
"cell_type": "code",
153-
"execution_count": 24,
153+
"execution_count": 4,
154154
"metadata": {},
155155
"outputs": [
156156
{
@@ -159,7 +159,7 @@
159159
"((1, 0, 2), (1, 0))"
160160
]
161161
},
162-
"execution_count": 24,
162+
"execution_count": 4,
163163
"metadata": {},
164164
"output_type": "execute_result"
165165
}
@@ -184,7 +184,7 @@
184184
"cell_type": "markdown",
185185
"metadata": {},
186186
"source": [
187-
"## Q6\n",
187+
"## Q6 - Quel est le coût de cette fonction ?\n",
188188
"\n",
189189
"Si $i$ et $j$ sont les dimensions de deux tables, c'est $O((i!)(j!))$."
190190
]
@@ -193,12 +193,14 @@
193193
"cell_type": "markdown",
194194
"metadata": {},
195195
"source": [
196-
"## Q7"
196+
"## Q7 - C'est b eaucoup trop long.\n",
197+
"\n",
198+
"On prop ose que calculer chaque p ermutation séparément. On cherche donc la meilleure p ermutation qui minimise la distribution de la somme par ligne et par colonne entre les deux matrices. Ecrire une fonctionne qui implémente ce raisonnement.\n"
197199
]
198200
},
199201
{
200202
"cell_type": "code",
201-
"execution_count": 25,
203+
"execution_count": 6,
202204
"metadata": {},
203205
"outputs": [
204206
{
@@ -207,7 +209,7 @@
207209
"((0, 1), (1, 0, 2))"
208210
]
209211
},
210-
"execution_count": 25,
212+
"execution_count": 6,
211213
"metadata": {},
212214
"output_type": "execute_result"
213215
}
@@ -244,45 +246,162 @@
244246
{
245247
"cell_type": "markdown",
246248
"metadata": {},
247-
"source": []
249+
"source": [
250+
"## Q8 - Mais c'est encore trop coûteux.\n",
251+
"\n",
252+
"On cherche la matrice M qui minimise AM =B\n",
253+
"où A et B sont les sommes sur les colonnes où lignes des matrices de statistiques observées sur deux années."
254+
]
255+
},
256+
{
257+
"cell_type": "markdown",
258+
"metadata": {},
259+
"source": [
260+
"Précisons d'abord ce qu'est une matrice de permutations $M$ : une matrice carrée dont les coefficients sont 0 ou 1. De plus, sur chaque ligne et chaque colonne, on ne trouve qu'un et un seul 1."
261+
]
248262
},
249263
{
250264
"cell_type": "code",
251-
"execution_count": null,
265+
"execution_count": 9,
252266
"metadata": {},
253-
"outputs": [],
267+
"outputs": [
268+
{
269+
"name": "stdout",
270+
"output_type": "stream",
271+
"text": [
272+
"A\n",
273+
"[[0 1]\n",
274+
" [2 3]\n",
275+
" [4 5]]\n",
276+
"M\n",
277+
"[[0 1 0]\n",
278+
" [0 0 1]\n",
279+
" [1 0 0]]\n",
280+
"M @ A\n",
281+
"[[2 3]\n",
282+
" [4 5]\n",
283+
" [0 1]]\n"
284+
]
285+
}
286+
],
254287
"source": [
255-
"import numpy as np\n",
256-
"\n",
288+
"M = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]])\n",
289+
"A = np.arange(6).reshape((3, -1))\n",
290+
"print(\"A\")\n",
291+
"print(A)\n",
292+
"print(\"M\")\n",
293+
"print(M)\n",
294+
"print(\"M @ A\")\n",
295+
"print(M @ A)"
296+
]
297+
},
298+
{
299+
"cell_type": "markdown",
300+
"metadata": {},
301+
"source": [
302+
"$MA$ permute les lignes, $AM$ permute les colonnes. Donc trouver la matrice $M$ qui minimise $\\lVert AM - B \\rVert^2$ où $B$ obtenue avec une permutation des colonnes de la matrice $A$ permettrait de déterminer cette permutation. Ce n'est pas un système d'équations en bonne et due forme mais c'en est un."
303+
]
304+
},
305+
{
306+
"cell_type": "code",
307+
"execution_count": 14,
308+
"metadata": {},
309+
"outputs": [
310+
{
311+
"name": "stdout",
312+
"output_type": "stream",
313+
"text": [
314+
"[[ 1.76711027 2.68346008]\n",
315+
" [-1.00760456 -1.85931559]]\n",
316+
"rang 2\n"
317+
]
318+
}
319+
],
320+
"source": [
321+
"M, _, rang, _ = np.linalg.lstsq(table1, table2)\n",
322+
"print(M)\n",
323+
"print(\"rang\", rang)"
324+
]
325+
},
326+
{
327+
"cell_type": "markdown",
328+
"metadata": {},
329+
"source": [
330+
"Le problème est qu'il y a plus d'inconnues que d'équations, d'où le rang faible (2). Avant de revenir à cette option. On part dans une autre direction. La plus grande des catégories de populations a beaucoup de chance d'être la plus grande l'année suivante. Donc la recherche du maximum dans les matrices A et B dévoile une partie de la matrice M. On applique cette idée aux sommes des lignes et des colonnes."
331+
]
332+
},
333+
{
334+
"cell_type": "code",
335+
"execution_count": 17,
336+
"metadata": {},
337+
"outputs": [
338+
{
339+
"data": {
340+
"text/plain": [
341+
"((0, 1), (2, 0, 1))"
342+
]
343+
},
344+
"execution_count": 17,
345+
"metadata": {},
346+
"output_type": "execute_result"
347+
}
348+
],
349+
"source": [
350+
"def optimise_vecteur_tri(vec1, vec2):\n",
351+
" pos_vec1 = [(v, i) for i, v in enumerate(vec1)]\n",
352+
" pos_vec1.sort()\n",
353+
" return tuple(p[1] for p in pos_vec1)\n",
257354
"\n",
258-
"coef = np.random.rand(5).reshape((-1, 1))\n",
259-
"coef[:, 0] = 1\n",
260-
"print(coef)\n",
261-
"t1 = np.ones((5, 1)) @ np.array([[5, 1, 2, 3, 4]], dtype=np.float32)\n",
262-
"t2 = np.ones((5, 1)) @ np.array([[2, 3, 1, 4, 5]], dtype=np.float32)\n",
263-
"M = np.array(\n",
264-
" [\n",
265-
" [0, 0, 1, 0, 0],\n",
266-
" [0, 0, 0, 1, 0],\n",
267-
" [0, 1, 0, 0, 0],\n",
268-
" [0, 0, 0, 0, 1],\n",
269-
" [1, 0, 0, 0, 0],\n",
270-
" ]\n",
271-
").T\n",
272355
"\n",
273-
"# Il faut diminuer le nombre de solutions pour n'en garder qu'une.\n",
274-
"for i in range(5):\n",
275-
" t1[i, t1[i, :] == i] = i + 0.01\n",
276-
" t2[i, t2[i, :] == i] = i + 0.01\n",
356+
"def optimise_fast_tri(table1, table2):\n",
357+
" return (\n",
358+
" optimise_vecteur_tri(table1.sum(axis=0), table2.sum(axis=0)),\n",
359+
" optimise_vecteur_tri(table1.sum(axis=1), table2.sum(axis=1)),\n",
360+
" )\n",
277361
"\n",
278-
"assert (t1 @ M - t2).max() < 1e-6\n",
279362
"\n",
280-
"m = np.linalg.lstsq(t1, t2)\n",
281-
"print(t1)\n",
282-
"print(t2)\n",
283-
"print(M)\n",
284-
"print((m[0] * 100).astype(int) / 100)"
363+
"optimise_fast_tri(table1, table2)"
285364
]
365+
},
366+
{
367+
"cell_type": "markdown",
368+
"metadata": {},
369+
"source": [
370+
"On revient au problème d'optimisation : $\\lVert AM - B \\rVert^2$. Il faudrait pouvoir forcer les coefficients de la matrice à être 0 ou 1 en ajoutant une contrainte. On utilise pour cela fonction $f(x)=x(1-X)$ qui vaut 0 quand $x \\epsilon \\{0,1\\}$. On cherche donc $M$ qui minimise $\\lVert AM - B \\rVert^2 + \\lambda \\lVert M^2*(1-M)^2\\rVert$ où $*$ est une multiplication terme à terme. Mais résoudre ce problème n'est pas simple. On en restera là pour le moment."
371+
]
372+
},
373+
{
374+
"cell_type": "markdown",
375+
"metadata": {},
376+
"source": [
377+
"## Q9 - Comment utiliser cette fonction p our implémenter une version plus rapide de la fonction à la question 5."
378+
]
379+
},
380+
{
381+
"cell_type": "markdown",
382+
"metadata": {},
383+
"source": [
384+
"Le code de la question précédente répond à la question."
385+
]
386+
},
387+
{
388+
"cell_type": "markdown",
389+
"metadata": {},
390+
"source": [
391+
"## Q10 - La troisième année, une colonne est coupée en deux : une catégorie est divisée en deux sous-catégorie. Que proposez-vous p our y remédier ?"
392+
]
393+
},
394+
{
395+
"cell_type": "markdown",
396+
"metadata": {},
397+
"source": [
398+
"L'idée est assez simple, on choisit au hasard deux lignes de la seconde matrice et on les aggrège. On la fonction précédente pour en déduire les deux permutations les moins coûteuses puis on conserve le coût de cette permutation. On fait pour toutes les paires et on ne garde que la meilleure paire."
399+
]
400+
},
401+
{
402+
"cell_type": "markdown",
403+
"metadata": {},
404+
"source": []
286405
}
287406
],
288407
"metadata": {

0 commit comments

Comments
 (0)