From ce234a51503c0668b2bbfead97347671dfb48df4 Mon Sep 17 00:00:00 2001 From: "Claude Haiku 4.5 (1M context)" Date: Sat, 7 Nov 2026 08:07:01 +0100 Subject: [PATCH 1/2] Fix(accents,#16638): restauration canonique des accents -- Search/Part3-Cas-pratiques (9 paires de jumeaux) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grain: MED/notebook-python — lane myia-po-2027:CoursIA-2 — prev: MED/guard #25032 Tranche deaccent de la famille Search/Part3-Cas-pratiques : 882 restaurations canoniques sur 14 carnets, markdown uniquement. - Fixer canonique : scripts/notebook_tools/restore_accents_canonical.py (4 lignes bright : markdown seul / pas les cibles de liens / pas le code / pas les sorties ni execution_count). - Table canonique etendue de 200 a 201 paires : ajout de "prerequis" -> "prérequis" (487 occurrences mesurees sur MyIA.AI.Notebooks/**, 436 carnets FR, 0 dans un carnet _en ; forme accentuee unique). - Preuve : 630 cellules inspectees, 182 cellules markdown modifiees, 0 cellule de code, 0 sortie, 0 execution_count, 0 diff non accentuel (comparaison fold(base) == fold(head) cellule par cellule). - Aucune re-execution due (C.2) : le diff ne touche que des cellules markdown. Co-Authored-By: Claude Haiku 5.5 --- .../App-12b-ConnectFour.ipynb | 48 +-- .../App-12c-ConnectFour.ipynb | 20 +- .../App-13-TSP-Metaheuristics.ipynb | 258 ++++++++-------- .../App-14-ConnectFour-Adversarial.ipynb | 116 +++---- .../App-15-SportsScheduling.ipynb | 84 ++--- .../App-15b-SportsScheduling-CSharp.ipynb | 64 ++-- .../App-17-VRP-Logistics.ipynb | 4 +- .../App-17b-VRP-Logistics-CSharp.ipynb | 20 +- .../App-19-ProceduralGeneration-WFC.ipynb | 50 +-- .../App-2-GraphColoring.ipynb | 286 +++++++++--------- .../App-20-SudokuBenchmark-Python.ipynb | 56 ++-- .../App-20b-SudokuBenchmark-CSharp.ipynb | 56 ++-- .../App-5-Timetabling-CSharp.ipynb | 46 +-- .../App-5-Timetabling.ipynb | 76 ++--- .../notebook_tools/detect_accent_stripping.py | 12 + 15 files changed, 604 insertions(+), 592 deletions(-) diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12b-ConnectFour.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12b-ConnectFour.ipynb index e035af36a23..4c08351ca92 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12b-ConnectFour.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12b-ConnectFour.ipynb @@ -183,7 +183,7 @@ "source": [ "### Classe Board\n", "\n", - "La classe `Board` encapsule l'etat du jeu et fournit les opérations fondamentales : coups legaux, placement de jeton, détection de victoire et affichage." + "La classe `Board` encapsule l'état du jeu et fournit les opérations fondamentales : coups legaux, placement de jeton, détection de victoire et affichage." ] }, { @@ -338,9 +338,9 @@ "| représentation | Matrice numpy 6x7, 0/1/2 |\n", "| Gravite | Les jetons s'empilent du bas vers le haut |\n", "| détection victoire | 4 directions : horizontale, verticale, 2 diagonales |\n", - "| Backtracking | `undo_move` permet de defaire un coup (utile pour Minimax) |\n", + "| Backtracking | `undo_move` permet de défaire un coup (utile pour Minimax) |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. La méthode `legal_moves()` vérifie la ligne supérieure (indice 0) : si elle est occupee, la colonne est pleine\n", "2. `check_win` parcourt les 4 directions avec des fenêtrès de taille 4 -- complexité O(ROWS x COLS)\n", "3. L'utilisation de `undo_move` évite de copier le plateau a chaque noeud de l'arbre de recherche" @@ -476,7 +476,7 @@ "\n", "**Sortie obtenue** : Le plateau apparaît avec les cercles rouge (joueur 1) et jaune (joueur 2) sur fond bleu, fidélément au jeu réel.\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. L'axe Y est inverse pour que la gravite soit naturelle (les jetons tombent vers le bas)\n", "2. Les cases vides sont affichees en bleu clair pour simuler les trous du plateau\n", "3. Cette visualisation sera réutilisée pour afficher les parties entre IA" @@ -704,9 +704,9 @@ "\n", "| Aspect | observation |\n", "|--------|-------------|\n", - "| Qualite de jeu | très faible : coups absurdes fréquents |\n", + "| Qualité de jeu | très faible : coups absurdes fréquents |\n", "| Temps par coup | Negligeable (cf. sortie cell. 13) |\n", - "| utilité | Baseline pour mesurer la qualite des autrès IA |\n", + "| utilité | Baseline pour mesurer la qualité des autrès IA |\n", "\n", "**Point cle** : Le joueur aléatoire ne détecte même pas les victoires immédiates. Il peut \"oublier\" de gagner ou de bloquer l'adversaire. C'est la pire IA possible -- tout algorithme raisonnable devrait le battre systématiquement." ] @@ -733,14 +733,14 @@ "- **Max** : le joueur courant maximise son score\n", "- **Min** : l'adversaire minimise le score du joueur courant\n", "\n", - "L'**elagage alpha-beta** permet de couper des branches de l'arbre sans perdre en qualite de décision :\n", + "L'**elagage alpha-beta** permet de couper des branches de l'arbre sans perdre en qualité de décision :\n", "- $\\alpha$ = meilleur score garanti pour Max sur le chemin courant\n", "- $\\beta$ = meilleur score garanti pour Min sur le chemin courant\n", "- Si $\\alpha \\geq \\beta$, on coupe (la branche ne sera jamais choisie)\n", "\n", "### Fonction d'évaluation\n", "\n", - "Pour limiter la profondeur de recherche, il faut une **fonction d'évaluation** qui estime la qualite d'une position non terminale. Notre évaluation analyse les fenêtrès de 4 cases :\n", + "Pour limiter la profondeur de recherche, il faut une **fonction d'évaluation** qui estime la qualité d'une position non terminale. Notre évaluation analyse les fenêtrès de 4 cases :\n", "\n", "| Configuration dans une fenêtre de 4 | Score |\n", "|--------------------------------------|-------|\n", @@ -1012,7 +1012,7 @@ "source": [ "### Test : Minimax vs Random\n", "\n", - "vérifions que Minimax domine clairement le joueur aléatoire. Nous utilisons une profondeur de 4 pour un bon compromis qualite/vitesse." + "vérifions que Minimax domine clairement le joueur aléatoire. Nous utilisons une profondeur de 4 pour un bon compromis qualité/vitesse." ] }, { @@ -1123,11 +1123,11 @@ "\n", "| Aspect | Minimax (d=4) | Random |\n", "|--------|---------------|--------|\n", - "| Qualite de jeu | Bonne (détecte menaces a 4 coups) | Nulle |\n", + "| Qualité de jeu | Bonne (détecte menaces a 4 coups) | Nulle |\n", "| Temps par coup | fraction de seconde (cell. 20) | negligeable (cell. 20) |\n", "| stratégie | Offensive et defensive | Aucune |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. Minimax gagne rapidement car il exploite les erreurs du joueur aléatoire\n", "2. L'elagage alpha-beta réduit considérablement le nombre de noeuds explores\n", "3. L'ordonnancement des coups (centre en premier) améliore l'efficacité de l'elagage" @@ -1149,7 +1149,7 @@ "source": [ "### Experiment : Effet de la profondeur\n", "\n", - "Comparons trois profondeurs de Minimax pour observer le compromis qualite/temps. Chaque profondeur joue 10 parties contre le joueur aléatoire." + "Comparons trois profondeurs de Minimax pour observer le compromis qualité/temps. Chaque profondeur joue 10 parties contre le joueur aléatoire." ] }, { @@ -1278,7 +1278,7 @@ "\n", "**Temps de calcul** : mesure live par la cellule 23 (croissance d’environ un ordre de grandeur par niveau de profondeur ; voir la sortie « ms/coup »).\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. même d=2 suffit contre un joueur aléatoire (10/10 victoires)\n", "2. Le temps croit **exponentiellement** avec la profondeur : $O(b^d)$ ou $b \\approx 4$ en moyenne\n", "3. L'elagage alpha-beta réduit la complexité de $O(b^d)$ a $O(b^{d/2})$ dans le meilleur cas\n", @@ -1496,7 +1496,7 @@ "source": [ "### Test : MCTS vs Minimax\n", "\n", - "Faisons s'affronter MCTS (1000 itérations) contre Minimax (profondeur 4) pour observer la qualite de jeu des deux approches." + "Faisons s'affronter MCTS (1000 itérations) contre Minimax (profondeur 4) pour observer la qualité de jeu des deux approches." ] }, { @@ -1730,7 +1730,7 @@ "| Profondeur | variable (adaptative) | Fixe (4 niveaux) |\n", "| Temps par coup | plus lent (cell. 28) | plus rapide (cell. 28) |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. Sur cette partie, MCTS(1000) l'emporte mais il est ~7x plus lent par coup que Minimax(d=4)\n", "2. MCTS n'a **pas besoin de fonction d'évaluation artisanale**\n", "3. MCTS explore automatiquement plus profondement les lignes prometteuses\n", @@ -1877,7 +1877,7 @@ "| Force | détecte les victoires et menaces immédiates |\n", "| Faiblesse | Pas de vision stratégique a long terme |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. Le glouton est **extrêmêment rapide** car il ne construit pas d'arbre\n", "2. Il détecte les coups gagnants et les menaces immédiates (profondeur 1)\n", "3. Il sera surpasse par Minimax qui voit plus loin dans l'arbre de jeu\n", @@ -1902,7 +1902,7 @@ "\n", "Organisons un tournoi complet entre toutes les IA. Chaque paire joue **6 parties** (3 en tant que joueur 1, 3 en tant que joueur 2) pour eliminer l'avantage du premier joueur.\n", "\n", - "> **Note** : Le nombre de parties a ete réduit a 6 pour ce notebook pedagogique. Pour des résultats statistiquement significatifs, utilisez 20+ parties par paire.\n", + "> **Note** : Le nombre de parties a ete réduit a 6 pour ce notebook pédagogique. Pour des résultats statistiquement significatifs, utilisez 20+ parties par paire.\n", "\n", "### Participants\n", "\n", @@ -2245,7 +2245,7 @@ "tags": [] }, "source": [ - "Visualisons ces résultats sous forme de graphiques pour mieux comparer les performances relatives et les couts en temps de calcul." + "Visualisons ces résultats sous forme de graphiques pour mieux comparer les performances relatives et les coûts en temps de calcul." ] }, { @@ -2362,11 +2362,11 @@ "| 4 | Greedy | Moyenne | Negligeable | Bloque les menaces immédiates |\n", "| 5 | Random | Nulle | Negligeable | Perd contre tout (0W-0D-6L partout) |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **La profondeur compte** : Minimax(d=6) domine Minimax(d=4) car il voit plus loin\n", "2. **MCTS(500) est competitif** sans fonction d'évaluation artisanale -- il prend même 2 parties a Minimax(d=6)\n", - "3. **Greedy est un bon rapport qualite/prix** : presque instantané, il bat Random a chaque fois\n", - "4. **Le compromis temps/qualite** est clairement visible dans le graphique de droite\n", + "3. **Greedy est un bon rapport qualité/prix** : presque instantané, il bat Random a chaque fois\n", + "4. **Le compromis temps/qualité** est clairement visible dans le graphique de droite\n", "5. **L'avantage du premier joueur** est partiellement neutralise par les 3+3 parties alternees\n", "\n", "> **observation** : Augmenter les itérations de MCTS (5000+) ou la profondeur de Minimax (d=8) améliorérait les performances, mais au prix d'un temps de calcul significativement plus élevé.\n" @@ -2390,7 +2390,7 @@ "\n", "### 8.1 Le framework Game de Russell & Norvig\n", "\n", - "Le livre **\"Artificial Intelligence: A Modern Approach\"** (AIMA) de Russell et Norvig propose un framework elegant pour les jeux a deux joueurs. Ce framework est disponible dans le module `games4e.py` du depot [aima-python](https://github.com/aimacode/aima-python), avec une implementation Java plus sophistiquee dans [aima-java](https://github.com/aimacode/aima-java).\n", + "Le livre **\"Artificial Intelligence: A Modern Approach\"** (AIMA) de Russell et Norvig propose un framework elegant pour les jeux a deux joueurs. Ce framework est disponible dans le module `games4e.py` du dépôt [aima-python](https://github.com/aimacode/aima-python), avec une implementation Java plus sophistiquee dans [aima-java](https://github.com/aimacode/aima-java).\n", "\n", "**Principe cle** : séparer la **logique du jeu** (classe Game) des **algorithmes de recherche** (fonctions joueurs).\n", "\n", @@ -3530,7 +3530,7 @@ "\n", "### Lecons retenues\n", "\n", - "1. **Profondeur vs Qualite** : Minimax gagne ~200 ELO par niveau de profondeur supplémentaire, au prix d'un facteur ~10x en temps de calcul.\n", + "1. **Profondeur vs Qualité** : Minimax gagne ~200 ELO par niveau de profondeur supplémentaire, au prix d'un facteur ~10x en temps de calcul.\n", "\n", "2. **Alpha-Beta essentiel** : L'elagage réduit le facteur de branchement effectif de ~7 a ~3-4, rendant les profondeurs 5-6 accessibles.\n", "\n", @@ -3543,7 +3543,7 @@ "### Pour aller plus loin\n", "\n", "- **résolution complète** : utiliser une base de données d'ouvertures (solution parfaite connue depuis 1988)\n", - "- **deep reinforcement learning (DQN, etc.)** : hors scope de ce carnet — voir l'EPIC DQN-RL dedie (a venir). Les methodes implementees ici (Minimax α-β, MCTS, AIMA) sont toutes des methodes de recherche classique, sans composante apprentissage.\n", + "- **deep reinforcement learning (DQN, etc.)** : hors scope de ce carnet — voir l'EPIC DQN-RL dedie (a venir). Les méthodes implementees ici (Minimax α-β, MCTS, AIMA) sont toutes des méthodes de recherche classique, sans composante apprentissage.\n", "- **Parallelisation** : Paralleliser MCTS ou Alpha-Beta pour explorer plus de noeuds\n", "- **recherche de Monte Carlo améliorée** : Ajouter une heuristique de simulation (RAVE, etc.)\n" ] diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12c-ConnectFour.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12c-ConnectFour.ipynb index 0bd169eba57..19ab0b4b61e 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12c-ConnectFour.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-12c-ConnectFour.ipynb @@ -11,11 +11,11 @@ "\n", "**Serie** : Search / Part3-Cas-pratiques (Bonus) — jumeau .NET du notebook Python [App-12b-ConnectFour](App-12b-ConnectFour.ipynb).\n", "\n", - "**Duree estimee** : ~1h30\n", + "**Durée estimee** : ~1h30\n", "\n", - "**Prerequis** : [Search-06-AdversarialSearch](../Part1-Foundations/Search-06-AdversarialSearch.ipynb) (Minimax, Alpha-Beta), [Search-07-MCTS](../Part1-Foundations/Search-07-MCTS-And-Beyond.ipynb), notions de C# / .NET.\n", + "**Prérequis** : [Search-06-AdversarialSearch](../Part1-Foundations/Search-06-AdversarialSearch.ipynb) (Minimax, Alpha-Beta), [Search-07-MCTS](../Part1-Foundations/Search-07-MCTS-And-Beyond.ipynb), notions de C# / .NET.\n", "\n", - "**Pourquoi un jumeau C# ?** Le notebook Python compare 5 intelligences artificielles (aleatoire, Minimax avec elagage alpha-beta, MCTS, glouton, iterative deepening) sur le jeu de Puissance 4, en s'appuyant sur `numpy` et `matplotlib`. Ce jumeau reimplemente les mêmes algorithmes en **C# .NET 9 (BCL seule, 0 NuGet)** : moteur de jeu, heuristique de fenêtre, Minimax alpha-beta, MCTS (UCB1), tournoi round-robin et iterative deepening. Les graphiques `matplotlib` sont remplacés par un rendu **ASCII autonome**. Les deux notebooks derivent les mêmes résultats (echelle de profondeur, tournoi).\n" + "**Pourquoi un jumeau C# ?** Le notebook Python compare 5 intelligences artificielles (aléatoire, Minimax avec elagage alpha-beta, MCTS, glouton, iterative deepening) sur le jeu de Puissance 4, en s'appuyant sur `numpy` et `matplotlib`. Ce jumeau reimplemente les mêmes algorithmes en **C# .NET 9 (BCL seule, 0 NuGet)** : moteur de jeu, heuristique de fenêtre, Minimax alpha-beta, MCTS (UCB1), tournoi round-robin et iterative deepening. Les graphiques `matplotlib` sont remplacés par un rendu **ASCII autonome**. Les deux notebooks derivent les mêmes résultats (echelle de profondeur, tournoi).\n" ] }, { @@ -25,10 +25,10 @@ "source": [ "## 1. Introduction\n", "\n", - "Le Puissance 4 est un jeu de stratégie combinatoire abstrait a information complete : deux joueurs (Rouge = joueur 1, Jaune = joueur 2) s'affrontent sur un plateau 6x7 en cherchant a aligner 4 jetons. Sa profondeur de jeu limitee (42 coups maximum) et son espace d'etats reduit (~4.5 trillions mais très echantillonnable) en font un banc d'essai ideal pour comparer des algorithmes de decision.\n", + "Le Puissance 4 est un jeu de stratégie combinatoire abstrait a information complete : deux joueurs (Rouge = joueur 1, Jaune = joueur 2) s'affrontent sur un plateau 6x7 en cherchant a aligner 4 jetons. Sa profondeur de jeu limitee (42 coups maximum) et son espace d'états réduit (~4.5 trillions mais très echantillonnable) en font un banc d'essai ideal pour comparer des algorithmes de decision.\n", "\n", "Ce notebook met en compétition **5 approches** :\n", - "1. **Joueur aleatoire** (baseline)\n", + "1. **Joueur aléatoire** (baseline)\n", "2. **Minimax avec elagage alpha-beta** (recherche exhaustive avec heuristique)\n", "3. **Monte Carlo Tree Search (MCTS)** (recherche statistique par simulations)\n", "4. **Joueur glouton** (heuristique immediate, 1-ply)\n", @@ -534,7 +534,7 @@ "source": [ "## 3. Heuristique de position (fenêtres de 4)\n", "\n", - "L'evaluation du plateau pour Minimax repose sur le decompte des **fenêtres de 4 cases** contigues (horizontales, verticales, diagonales). Pour chaque fenêtre :\n", + "L'évaluation du plateau pour Minimax repose sur le decompte des **fenêtres de 4 cases** contigues (horizontales, verticales, diagonales). Pour chaque fenêtre :\n", "- 4 jetons du joueur : **+1000** (gagnant)\n", "- 3 jetons + 1 vide : **+10** (pres de gagner)\n", "- 2 jetons + 2 vides : **+2** (potential)\n", @@ -850,7 +850,7 @@ "source": [ "### Expérience : effet de la profondeur\n", "\n", - "Plus la profondeur de recherche augmente, plus Minimax anticipe loin — au prix du temps de calcul (croissance exponentielle). On mesure le **taux de victoire** et le **temps par coup** pour les profondeurs 2, 4 et 6 contre le joueur aleatoire.\n" + "Plus la profondeur de recherche augmente, plus Minimax anticipe loin — au prix du temps de calcul (croissance exponentielle). On mesure le **taux de victoire** et le **temps par coup** pour les profondeurs 2, 4 et 6 contre le joueur aléatoire.\n" ] }, { @@ -922,7 +922,7 @@ "source": [ "## 5. IA 3 : Monte Carlo Tree Search (MCTS)\n", "\n", - "MCTS construit progressivement un arbre de jeu par **simulations aleatoires** (rollouts). Chaque noeud choisit ses enfants via **UCB1** (Upper Confidence Bound) qui equilibre exploitation (moyenne des recompenses) et exploration (visites rares). Après un budget d'itérations, on joue le coup le plus visite.\n" + "MCTS construit progressivement un arbre de jeu par **simulations aléatoires** (rollouts). Chaque noeud choisit ses enfants via **UCB1** (Upper Confidence Bound) qui equilibre exploitation (moyenne des récompenses) et exploration (visites rares). Après un budget d'itérations, on joue le coup le plus visite.\n" ] }, { @@ -1964,7 +1964,7 @@ "Ce jumeau C# a reimplemente, sans aucune librairie externe, le banc d'essai comparatif du notebook Python :\n", "\n", "- **Moteur de jeu** complet (plateau 6x7, legalite, victoire, undo pour backtracking)\n", - "- **5 algorithmes** : joueur aleatoire, glouton (1-ply), Minimax alpha-beta, MCTS (UCB1), iterative deepening\n", + "- **5 algorithmes** : joueur aléatoire, glouton (1-ply), Minimax alpha-beta, MCTS (UCB1), iterative deepening\n", "- **Heuristique de fenêtres** (4 alignes +1000, 3+vide +10, etc., bonus centre)\n", "- **Tournoi round-robin** revelant la hiérarchie des algorithmes\n", "\n", @@ -1982,7 +1982,7 @@ "\n", "### Pathologie de l'arbre de jeu (note honnete, G.1)\n", "\n", - "Le tournoi revele un résultat contre-intuitif mais **reel et documente** : **Minimax(d=2) bat Minimax(d=4)** dans cette configuration (match aller-retour 4-0 dans les deux sens). Ce n'est pas un bug — le moteur et l'heuristique sont verifies (scores de position re-derives a la main, P1=9/P2=5 sur le plateau de demo). C'est la **pathologie de la recherche dans les arbres de jeu** (Nau, 1982) : avec une heuristique *imparfaite*, une recherche plus profonde peut systematiquement perdre contre une recherche moins profonde, parce que l'effet d'horizon fait sur-evaluer des menaces qui ne se realisent jamais. Les matchs Minimax-vs-Minimax etant **déterministes** (aucun aleatoire dans la recherche), le même coup est joue a chaque partie — d'ou des scores 4-0 nets. L'avantage du **premier joueur** (P1 = Rouge) est également massif au Puissance 4 (victoire forcee en jeu parfait). Ce phenomene est une lecon pedagogique centrale : « plus profond » n'implique pas « meilleur » des qu'on s'ecarte du jeu parfait. Les **valeurs numériques exactes** (temps, compteurs) différent C# vs Python (JIT .NET plus rapide que CPython) — c'est un effet runtime attendu, pas une différence algorithmique.\n", + "Le tournoi revele un résultat contre-intuitif mais **réel et documente** : **Minimax(d=2) bat Minimax(d=4)** dans cette configuration (match aller-retour 4-0 dans les deux sens). Ce n'est pas un bug — le moteur et l'heuristique sont verifies (scores de position re-derives a la main, P1=9/P2=5 sur le plateau de demo). C'est la **pathologie de la recherche dans les arbres de jeu** (Nau, 1982) : avec une heuristique *imparfaite*, une recherche plus profonde peut systematiquement perdre contre une recherche moins profonde, parce que l'effet d'horizon fait sur-evaluer des menaces qui ne se realisent jamais. Les matchs Minimax-vs-Minimax etant **déterministes** (aucun aléatoire dans la recherche), le même coup est joue a chaque partie — d'ou des scores 4-0 nets. L'avantage du **premier joueur** (P1 = Rouge) est également massif au Puissance 4 (victoire forcee en jeu parfait). Ce phenomene est une lecon pédagogique centrale : « plus profond » n'implique pas « meilleur » des qu'on s'ecarte du jeu parfait. Les **valeurs numériques exactes** (temps, compteurs) différent C# vs Python (JIT .NET plus rapide que CPython) — c'est un effet runtime attendu, pas une différence algorithmique.\n", "\n", "### Prochaines étapes\n", "\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-13-TSP-Metaheuristics.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-13-TSP-Metaheuristics.ipynb index 68f1b07aa39..cbfba74f87d 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-13-TSP-Metaheuristics.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-13-TSP-Metaheuristics.ipynb @@ -26,12 +26,12 @@ "3. **Appliquer** des métaheuristiques (Recuit Simule, AG, ACO)\n", "4. **Comparer** les performances avec OR-Tools et l'amelioration 2-opt\n", "\n", - "### Prerequis\n", + "### Prérequis\n", "- Python 3.10+ (numpy, matplotlib, scipy)\n", "- Search-4 : Recherche locale (Simulated Annealing)\n", "- Search-5 : Algorithmes génétiques\n", "\n", - "### Duree estimee : 50 minutes\n", + "### Durée estimee : 50 minutes\n", "\n", "> **Source** : Adapte du projet etudiant ECE 2026 -- Groupe 03 (MonteiroTour).\n", ">\n", @@ -79,17 +79,17 @@ "\n", "### Definition\n", "\n", - "Le **Probleme du Voyageur de Commerce** (TSP -- Traveling Salesman Problem) est un probleme d'optimisation combinatoire classique : trouver le plus court cycle passant par N villes exactement une fois chacune. La formalisation rigoureuse (Karl Menger 1930, Hassler Whitney 1948) introduit les notions de **tournee hamiltonienne** et de **cycle de cout minimal** dans un graphe complet pondere.\n", + "Le **Problème du Voyageur de Commerce** (TSP -- Traveling Salesman Problem) est un problème d'optimisation combinatoire classique : trouver le plus court cycle passant par N villes exactement une fois chacune. La formalisation rigoureuse (Karl Menger 1930, Hassler Whitney 1948) introduit les notions de **tournee hamiltonienne** et de **cycle de coût minimal** dans un graphe complet pondere.\n", "\n", - "**Pourquoi TSP est un cas d'etude pedagogique privilegie** :\n", - "1. **Simplicite du probleme** : la definition tient en une phrase (cycle hamiltonien de cout minimal). Tout etudiant peut comprendre l'enonce.\n", - "2. **Difficulte de l'optimisation** : la complexite est NP-difficile (sans algorithme polynomial connu), donc les methodes exactes explosent exponentiellement au-dela de N=15.\n", - "3. **Richesse des methodes** : de la force brute aux algorithmes evolutionnaires, le TSP se pretent a une comparaison methodologique structuree (cf. tableau synthese du notebook).\n", + "**Pourquoi TSP est un cas d'étude pédagogique privilegie** :\n", + "1. **Simplicite du problème** : la definition tient en une phrase (cycle hamiltonien de coût minimal). Tout etudiant peut comprendre l'enonce.\n", + "2. **Difficulte de l'optimisation** : la complexité est NP-difficile (sans algorithme polynomial connu), donc les méthodes exactes explosent exponentiellement au-dela de N=15.\n", + "3. **Richesse des méthodes** : de la force brute aux algorithmes evolutionnaires, le TSP se pretent a une comparaison methodologique structuree (cf. tableau synthese du notebook).\n", "4. **Application industrielle** : logistique (livraisons, tournes), circuits electroniques (VLSI), ordre de visitation en robotique.\n", "\n", "### Applications reelles\n", "\n", - "Le TSP modelise des problemes d'optimisation concrets :\n", + "Le TSP modelise des problèmes d'optimisation concrets :\n", "\n", "- **Logistique** : Tournees de livraison, collecte de dechets.\n", "- **Fabrication** : Percage de circuits imprimes, decoupe laser.\n", @@ -99,9 +99,9 @@ "**Trois variantes canoniques** :\n", "- **TSP symetrique** : `d(i, j) = d(j, i)` (cas par defaut du notebook).\n", "- **TSP asymetrique (ATSP)** : `d(i, j) != d(j, i)` (cf. Bonus 1, code[16]).\n", - "- **TSP avec fenetre horaire (TSPTW)** : chaque ville doit etre visitee dans une fenetre [a_i, b_i] (extension classique).\n", + "- **TSP avec fenêtre horaire (TSPTW)** : chaque ville doit etre visitee dans une fenêtre [a_i, b_i] (extension classique).\n", "\n", - "**Note d'ancrage sur la suite du notebook** : le notebook utilise `TSPInstance.generer_aleatoire(n, graine)` pour creer des instances aleatoires reproductibles. La matrice de distances est symetrique par defaut, calculee comme `d(i, j) = sqrt((x_i - x_j)^2 + (y_i - y_j)^2)` entre coordonnees 2D.\n" + "**Note d'ancrage sur la suite du notebook** : le notebook utilise `TSPInstance.generer_aleatoire(n, graine)` pour créer des instances aléatoires reproductibles. La matrice de distances est symetrique par defaut, calculee comme `d(i, j) = sqrt((x_i - x_j)^2 + (y_i - y_j)^2)` entre coordonnees 2D.\n" ] }, { @@ -180,18 +180,18 @@ "tags": [] }, "source": [ - "## 2. Formalisation du Probleme\n", + "## 2. Formalisation du Problème\n", "\n", - "Nous allons definir une classe `TSPInstance` pour representer une instance du probleme, avec une matrice de distances NxN et une methode d'affichage.\n", + "Nous allons définir une classe `TSPInstance` pour representer une instance du problème, avec une matrice de distances NxN et une méthode d'affichage.\n", "\n", - "**Pourquoi une classe et pas un simple dict** : la classe encapsule la generation aleatoire et l'affichage. Cela permet d'instancier plusieurs TSP-10 / TSP-20 / TSP-50 sans dupliquer le code. C'est aussi une bonne pratique pedagogique (montre comment structurer un solveur en POO plutot qu'en scripts lineaires).\n", + "**Pourquoi une classe et pas un simple dict** : la classe encapsule la generation aléatoire et l'affichage. Cela permet d'instancier plusieurs TSP-10 / TSP-20 / TSP-50 sans dupliquer le code. C'est aussi une bonne pratique pédagogique (montre comment structurer un solveur en POO plutot qu'en scripts lineaires).\n", "\n", - "**Lien avec la complexite** :\n", + "**Lien avec la complexité** :\n", "- Une matrice de distances NxN contient N^2 entrees (ici 100 pour TSP-10).\n", "- Le nombre de tournees possibles est (N-1)! / 2 = 9! / 2 = 181 440 pour N=10.\n", - "- Pour N=15 : 14! / 2 ≈ 4.36 × 10^10, deja au-dela de l'exploration exhaustive raisonnable.\n", + "- Pour N=15 : 14! / 2 ≈ 4.36 × 10^10, déjà au-dela de l'exploration exhaustive raisonnable.\n", "\n", - "**Implication pedagogique** : la formalisation explicite (classe + matrice + geometrie) prepare le terrain pour les methodes qui suivent. Les etudiants peuvent modifier la classe (par exemple, ajouter des coordonnees 3D) sans casser les solveurs." + "**Implication pédagogique** : la formalisation explicite (classe + matrice + geometrie) prepare le terrain pour les méthodes qui suivent. Les etudiants peuvent modifier la classe (par exemple, ajouter des coordonnees 3D) sans casser les solveurs." ] }, { @@ -328,12 +328,12 @@ "id": "a1ee29f0", "metadata": {}, "source": [ - "**Sortie observee de code[1]** (verbatim) : `Instance: TSP-10 / Nombre de villes: 10 / Matrice de distances: shape (10, 10)`. La cellule definit la classe `TSPInstance` avec :\n", - "- Un constructeur prenant le nombre de villes, une matrice de distances optionnelle, et une graine aleatoire.\n", - "- Une methode `generer_aleatoire(n, graine)` qui produit une instance avec coordonnees 2D uniformes dans [0, 100].\n", - "- Une methode `afficher()` qui affiche un resume de l'instance (nom, N, matrice).\n", + "**Sortie observee de code[1]** (verbatim) : `Instance: TSP-10 / Nombre de villes: 10 / Matrice de distances: shape (10, 10)`. La cellule définit la classe `TSPInstance` avec :\n", + "- Un constructeur prenant le nombre de villes, une matrice de distances optionnelle, et une graine aléatoire.\n", + "- Une méthode `generer_aleatoire(n, graine)` qui produit une instance avec coordonnees 2D uniformes dans [0, 100].\n", + "- Une méthode `afficher()` qui affiche un resume de l'instance (nom, N, matrice).\n", "\n", - "**Sortie observee de code[1] -- visualisation** : la cellule inclut aussi une visualisation matplotlib de l'instance (10 points disperses dans le carre [0, 100] x [0, 100]). C'est le point d'entree visuel pour comprendre la geometrie du probleme." + "**Sortie observee de code[1] -- visualisation** : la cellule inclut aussi une visualisation matplotlib de l'instance (10 points disperses dans le carre [0, 100] x [0, 100]). C'est le point d'entree visuel pour comprendre la geometrie du problème." ] }, { @@ -350,18 +350,18 @@ "tags": [] }, "source": [ - "## 3. Methodes Exates (Reference)\n", + "## 3. Méthodes Exates (Reference)\n", "\n", "### 3.1 Force Brute\n", "\n", - "Exploration de toutes les tournees possibles (N! / 2) et selection de la meilleure. Complexite exponentielle : faisable jusqu'a N=12 sur machine moderne.\n", + "Exploration de toutes les tournees possibles (N! / 2) et sélection de la meilleure. Complexité exponentielle : faisable jusqu'a N=12 sur machine moderne.\n", "\n", "**Note d'application industrielle** : la force brute est inutilisable au-dela de N=15. Les solveurs industriels utilisent :\n", - "- **Branch and bound** (Held-Karp 1962) : complexite O(N^2 · 2^N) au lieu de O(N!), divisant le cout par ~N.\n", + "- **Branch and bound** (Held-Karp 1962) : complexité O(N^2 · 2^N) au lieu de O(N!), divisant le coût par ~N.\n", "- **Programmation dynamique** : expo(N) memoire, expo(N) temps, optimal garanti.\n", - "- **Concorde TSP Solver** (Applegate et al. 2006) : etat de l'art pour les instances jusqu'a N=85 000.\n", + "- **Concorde TSP Solver** (Applegate et al. 2006) : état de l'art pour les instances jusqu'a N=85 000.\n", "\n", - "**Implication pedagogique** : la force brute est la seule methode de ce carnet qui garantit l'optimum, au prix d'une croissance factorielle du temps." + "**Implication pédagogique** : la force brute est la seule méthode de ce carnet qui garantit l'optimum, au prix d'une croissance factorielle du temps." ] }, { @@ -441,15 +441,15 @@ "metadata": {}, "source": [ "**Sortie observee de code[2]** (verbatim, instance TSP-10 de `code[1]`) : `Solution optimale: 290.31 / Temps de calcul: 0.672s`. La cellule implemente `brute_force(tsp)` qui :\n", - "- Fixe la ville 0 comme point de depart (pour eliminer les rotations).\n", + "- Fixe la ville 0 comme point de départ (pour eliminer les rotations).\n", "- Genere toutes les permutations des N-1 villes restantes.\n", - "- Calcule le cout de chaque tournee et garde le minimum.\n", + "- Calcule le coût de chaque tournee et garde le minimum.\n", "\n", "**Pourquoi 0.672 s pour TSP-10** : `itertools.permutations(range(1, 10))` produit 9! = 362 880 permutations, chacune evaluee par `cout_tournee` (boucle Python sur les 10 aretes). Le temps mesure dans la sortie committee est de 0.672 s. Le nombre de permutations croit factoriellement avec N, et le temps avec lui : c'est la limite pratique de la force brute.\n", "\n", - "**Sortie observee de code[2] -- visualisation** : la cellule inclut aussi la visualisation de la tournee optimale (un polygone ferme reliant les 10 villes dans l'ordre optimal, avec cout total 290.31 superpose en legende).\n", + "**Sortie observee de code[2] -- visualisation** : la cellule inclut aussi la visualisation de la tournee optimale (un polygone ferme reliant les 10 villes dans l'ordre optimal, avec coût total 290.31 superpose en legende).\n", "\n", - "**Lecture de cette valeur** : 290.31 est l'optimum exact de l'instance TSP-10 (`code[1]`). Les heuristiques des sections suivantes tournent sur des instances de 20 et 30 villes : leur cout n'est donc pas compare a cet optimum, qui sert ici de reference exacte autonome." + "**Lecture de cette valeur** : 290.31 est l'optimum exact de l'instance TSP-10 (`code[1]`). Les heuristiques des sections suivantes tournent sur des instances de 20 et 30 villes : leur coût n'est donc pas compare a cet optimum, qui sert ici de reference exacte autonome." ] }, { @@ -472,13 +472,13 @@ "\n", "Construction d'une tournee en partant d'une ville et en ajoutant iterativement la ville la plus proche non encore visitee.\n", "\n", - "**Caracteristiques du NN** :\n", - "- **Complexite temporelle** : O(N^2).\n", - "- **Complexite spatiale** : O(N) (tableau de visitation).\n", - "- **Gap typique** : 20-30 % au-dessus de l'optimal pour les instances aleatoires.\n", - "- **Determinisme** : la sortie depend du depart. Faire NN depuis chaque ville (N executions) et garder la meilleure ameliore le resultat.\n", + "**Caractéristiques du NN** :\n", + "- **Complexité temporelle** : O(N^2).\n", + "- **Complexité spatiale** : O(N) (tableau de visitation).\n", + "- **Gap typique** : 20-30 % au-dessus de l'optimal pour les instances aléatoires.\n", + "- **Determinisme** : la sortie depend du départ. Faire NN depuis chaque ville (N exécutions) et garder la meilleure ameliore le résultat.\n", "\n", - "**Lien avec le 2-opt (code[4])** : NN est generalement ameliore par 2-opt (qui inverse des sous-sequences pour eliminer les croisements), voir la section 5 et la sortie de code[4]." + "**Lien avec le 2-opt (code[4])** : NN est généralement ameliore par 2-opt (qui inverse des sous-sequences pour eliminer les croisements), voir la section 5 et la sortie de code[4]." ] }, { @@ -560,12 +560,12 @@ "source": [ "**Sortie observee de code[3]** (verbatim, instance TSP-20 de `tsp_medium`) : `Solution NN: 465.04 / Temps: 0.09ms`. La cellule implemente `plus_proche_voisin(tsp, depart=0)` qui :\n", "- Part de la ville `depart` (0 par defaut).\n", - "- A chaque etape, choisit la ville non visitee la plus proche (en matiere de distance euclidienne).\n", - "- Continue jusqu'a ce que toutes les villes soient visitees, puis retourne au point de depart.\n", + "- A chaque étape, choisit la ville non visitee la plus proche (en matiere de distance euclidienne).\n", + "- Continue jusqu'a ce que toutes les villes soient visitees, puis retourne au point de départ.\n", "\n", - "**Pourquoi 0.09 ms** : la complexite est O(N^2) (pour chaque ville, scan des N-1 voisines). Pour N=20, la boucle evalue N(N-1)/2 = 190 distances au total -- negligeable. La methode est donc rapide mais pas la meilleure : son cout (465.04) est nettement au-dessus de celui de 2-opt applique a ce meme depart (sortie de code[4], section 5).\n", + "**Pourquoi 0.09 ms** : la complexité est O(N^2) (pour chaque ville, scan des N-1 voisines). Pour N=20, la boucle evalue N(N-1)/2 = 190 distances au total -- negligeable. La méthode est donc rapide mais pas la meilleure : son coût (465.04) est nettement au-dessus de celui de 2-opt applique a ce même départ (sortie de code[4], section 5).\n", "\n", - "**Sortie observee de code[3] -- visualisation** : la cellule inclut la tournee NN visualisee (20 segments, retour au depart compris, cout 465.04 en legende). La structure montre les 'sauts' typiques du NN (traversees longues)." + "**Sortie observee de code[3] -- visualisation** : la cellule inclut la tournee NN visualisee (20 segments, retour au départ compris, coût 465.04 en legende). La structure montre les 'sauts' typiques du NN (traversees longues)." ] }, { @@ -591,12 +591,12 @@ "- Inverser la sous-sequence (v_i, v_{i+1}, ..., v_j) en (v_j, ..., v_i).\n", "- Si la nouvelle tournee est plus courte, accepter.\n", "\n", - "**Caracteristiques du 2-opt** :\n", - "- **Complexite temporelle** : O(N^2 · max_iterations).\n", - "- **Gap typique** : 5-10 % au-dessus de l'optimal depuis NN comme depart.\n", - "- **Determinisme** : le resultat depend de la strategie de choix (premier ameliorant vs meilleur ameliorant).\n", + "**Caractéristiques du 2-opt** :\n", + "- **Complexité temporelle** : O(N^2 · max_iterations).\n", + "- **Gap typique** : 5-10 % au-dessus de l'optimal depuis NN comme départ.\n", + "- **Determinisme** : le résultat depend de la stratégie de choix (premier ameliorant vs meilleur ameliorant).\n", "\n", - "**Note pedagogique** : 2-opt est le **bloc de construction fondamental** de la recherche locale moderne. Il est combine avec 3-opt, LK (Lin-Kernighan), et des variantes stochastiques dans les solveurs industriels." + "**Note pédagogique** : 2-opt est le **bloc de construction fondamental** de la recherche locale moderne. Il est combine avec 3-opt, LK (Lin-Kernighan), et des variantes stochastiques dans les solveurs industriels." ] }, { @@ -684,13 +684,13 @@ "source": [ "**Sortie observee de code[4]** (verbatim, instance TSP-20) : `Solution NN + 2-opt: 386.63 / Amelioration: 16.9% / Temps: 3.32ms`. La cellule implemente `two_opt(tsp, tournee, max_iter=1000)` qui :\n", "- Prend une tournee initiale (typiquement celle du NN).\n", - "- A chaque iteration, choisit deux aretes non adjacentes et les remplace par les deux aretes 'croisees' (ce qui inverse une sous-sequence).\n", - "- Accepte le mouvement si le cout total diminue.\n", + "- A chaque itération, choisit deux aretes non adjacentes et les remplace par les deux aretes 'croisees' (ce qui inverse une sous-sequence).\n", + "- Accepte le mouvement si le coût total diminue.\n", "- Continue jusqu'a convergence (aucune amelioration possible) ou max_iterations.\n", "\n", - "**Pourquoi 3.32 ms** : la complexite est O(N^2 · max_iter). Pour TSP-20, une passe examine 171 paires d'aretes (i, j), et chaque examen recalcule le cout complet de la tournee (O(N)) ; le temps mesure est celui de la sortie committee.\n", + "**Pourquoi 3.32 ms** : la complexité est O(N^2 · max_iter). Pour TSP-20, une passe examine 171 paires d'aretes (i, j), et chaque examen recalcule le coût complet de la tournee (O(N)) ; le temps mesure est celui de la sortie committee.\n", "\n", - "**Sortie observee de code[4] -- visualisation** : la cellule inclut la tournee NN + 2-opt visualisee (20 segments sans croisement, cout 386.63 en legende). Les croisements visibles dans NN (code[3]) sont elimines." + "**Sortie observee de code[4] -- visualisation** : la cellule inclut la tournee NN + 2-opt visualisee (20 segments sans croisement, coût 386.63 en legende). Les croisements visibles dans NN (code[3]) sont elimines." ] }, { @@ -709,19 +709,19 @@ "source": [ "## 6. Recuit Simule (Simulated Annealing)\n", "\n", - "Metaheuristique basee sur l'analogie avec le recuit physique : on accepte avec une probabilite decroissante des mouvements qui degradent la solution.\n", + "Métaheuristique basee sur l'analogie avec le recuit physique : on accepte avec une probabilite decroissante des mouvements qui degradent la solution.\n", "\n", - "**Caracteristiques du SA** :\n", - "- **Complexite temporelle** : O(n_iterations · N).\n", + "**Caractéristiques du SA** :\n", + "- **Complexité temporelle** : O(n_iterations · N).\n", "- **Gap typique** : 2-5 % au-dessus de l'optimal avec un bon schema de refroidissement.\n", - "- **Parametrage** : `temperature_initiale`, `temperature_finale`, `n_iterations`, `alpha` (taux de refroidissement, defaut 0.995), `iterations_par_T` (defaut 100) -- 6 hyperparametres a regler (T0, T_min, alpha, iterations_par_T, plus tournee_initiale et tsp).\n", + "- **Parametrage** : `temperature_initiale`, `temperature_finale`, `n_iterations`, `alpha` (taux de refroidissement, defaut 0.995), `iterations_par_T` (defaut 100) -- 6 hyperparamètres a regler (T0, T_min, alpha, iterations_par_T, plus tournee_initiale et tsp).\n", "\n", "**Schema de refroidissement** :\n", "- **Lineaire** : `T(t) = T_init - (T_init - T_fin) * t / n_iterations`. Simple mais peu adapte.\n", "- **Geometrique** : `T(t) = T_init * alpha^t` avec `alpha < 1`. Standard, equilibre exploration/exploitation.\n", "- **Cauchy** : `T(t) = T_init / (1 + t)`. Plus agressif en fin de course.\n", "\n", - "**Note pedagogique** : SA est l'archetype des **metaheuristiques a voisinages**. Il est robuste, parallele (chaque temperature peut etre simulee en parallele), et theoriquement convergent vers l'optimal si le refroidissement est suffisamment lent (preuve Geman & Geman 1984)." + "**Note pédagogique** : SA est l'archetype des **métaheuristiques a voisinages**. Il est robuste, parallele (chaque temperature peut etre simulee en parallele), et theoriquement convergent vers l'optimal si le refroidissement est suffisamment lent (preuve Geman & Geman 1984)." ] }, { @@ -903,17 +903,17 @@ "\n", "La sortie verbatim de code[5] est `Solution SA: 386.43 / Temps: 0.95s`, sur l'instance TSP-20 (`tsp_medium`). La cellule implemente `simulated_annealing_tsp(tsp, tournee_initiale, T0, T_min, alpha, iterations_par_T)` qui :\n", "- Part d'une solution initiale (typiquement NN + 2-opt).\n", - "- A chaque iteration, propose un mouvement swap (echange aleatoire de 2 villes ; ce notebook utilise un swap, pas un 2-opt classique).\n", + "- A chaque itération, propose un mouvement swap (echange aléatoire de 2 villes ; ce notebook utilise un swap, pas un 2-opt classique).\n", "- Accepte avec probabilite 1 si amelioration, `exp(-delta/T)` sinon.\n", "- Diminue `T` selon un schema de refroidissement.\n", "\n", - "**Pourquoi 0.95 s** : chacune des ~183 800 iterations recalcule le cout complet de la tournee candidate (`tsp.cout_tournee`, boucle sur les 20 villes) et copie la tournee (`tournee.copy()`). Le cout d'une iteration est donc O(N), et non O(1). Le temps mesure dans la sortie committee est de 0.95 s.\n", + "**Pourquoi 0.95 s** : chacune des ~183 800 itérations recalcule le coût complet de la tournee candidate (`tsp.cout_tournee`, boucle sur les 20 villes) et copie la tournee (`tournee.copy()`). Le coût d'une itération est donc O(N), et non O(1). Le temps mesure dans la sortie committee est de 0.95 s.\n", "\n", - "**Schema de refroidissement** : le notebook utilise un schema geometrique `T(t) = T0 * alpha^t` avec `alpha = 0.995` (defaut). Depuis `T0 = 1000` jusqu'a `T_min = 0.1`, le nombre de paliers est 1838 (log(0.1/1000)/log(0.995) ≈ 1837.5), soit ~183 800 iterations (100 par palier). Ce nombre ne depend pas de N.\n", + "**Schema de refroidissement** : le notebook utilise un schema geometrique `T(t) = T0 * alpha^t` avec `alpha = 0.995` (defaut). Depuis `T0 = 1000` jusqu'a `T_min = 0.1`, le nombre de paliers est 1838 (log(0.1/1000)/log(0.995) ≈ 1837.5), soit ~183 800 itérations (100 par palier). Ce nombre ne depend pas de N.\n", "\n", - "**Lecture du cout SA (386.43)** : il est comparable a NN + 2-opt (386.63), legerement meilleur sur cette instance de 20 villes. Ici SA n'apporte guere au-dela de 2-opt ; le benchmark de la section 9 (TSP-30) donne un ecart plus net entre les methodes.\n", + "**Lecture du coût SA (386.43)** : il est comparable a NN + 2-opt (386.63), legerement meilleur sur cette instance de 20 villes. Ici SA n'apporte guere au-dela de 2-opt ; le benchmark de la section 9 (TSP-30) donne un ecart plus net entre les méthodes.\n", "\n", - "**Note sur la convergence** (cf. code[6]) : la cellule de visualisation trace `historique_couts`, le meilleur cout enregistre apres chaque palier. Cette courbe est non croissante par construction (c'est le meilleur cout, jamais le cout courant) ; le carnet n'imprime aucun chiffre de convergence, il faut lire la figure." + "**Note sur la convergence** (cf. code[6]) : la cellule de visualisation trace `historique_couts`, le meilleur coût enregistre après chaque palier. Cette courbe est non croissante par construction (c'est le meilleur coût, jamais le coût courant) ; le carnet n'imprime aucun chiffre de convergence, il faut lire la figure." ] }, { @@ -930,19 +930,19 @@ "tags": [] }, "source": [ - "## 7. Algorithme Genetique\n", + "## 7. Algorithme Génétique\n", "\n", - "Optimisation par evolution artificielle : selection, croisement, mutation sur une population de tournees.\n", + "Optimisation par evolution artificielle : sélection, croisement, mutation sur une population de tournees.\n", "\n", - "**Caracteristiques du GA** :\n", - "- **Complexite temporelle** : O(n_generations · taille_population · N).\n", + "**Caractéristiques du GA** :\n", + "- **Complexité temporelle** : O(n_generations · taille_population · N).\n", "- **Gap typique** : 10-20 % au-dessus de l'optimal pour TSP-50, avec un bon reglage.\n", - "- **Parametrage** : `taille_population`, `n_generations`, `taux_croisement`, `taux_mutation`, `taille_tournoi` -- 5 hyperparametres.\n", + "- **Parametrage** : `taille_population`, `n_generations`, `taux_croisement`, `taux_mutation`, `taille_tournoi` -- 5 hyperparamètres.\n", "\n", - "**Operateurs de croisement** :\n", + "**Opérateurs de croisement** :\n", "- **OX (Order Crossover)** : preserve l'ordre relatif des villes. Standard pour TSP.\n", "- **PMX (Partially Mapped Crossover)** : preserve les positions absolues. Moins naturel pour TSP.\n", - "- **CX (Cycle Crossover)** : preserve les sous-cycles. Bon pour les problemes de partition." + "- **CX (Cycle Crossover)** : preserve les sous-cycles. Bon pour les problèmes de partition." ] }, { @@ -1090,18 +1090,18 @@ "metadata": {}, "source": [ "**Sortie observee de code[7]** (verbatim, instance TSP-20) : `Solution GA: 500.12 / Temps: 0.07s`. La cellule implemente `algorithme_genetique_tsp(tsp, taille_population, n_generations)` qui :\n", - "- Initialise une population de tournees aleatoires.\n", + "- Initialise une population de tournees aléatoires.\n", "- A chaque generation :\n", - " - **Selection** : tournoi de taille k parmi la population.\n", + " - **Sélection** : tournoi de taille k parmi la population.\n", " - **Croisement** : OX (Order Crossover) entre deux parents.\n", - " - **Mutation** : 2-opt sur une sous-sequence aleatoire.\n", + " - **Mutation** : 2-opt sur une sous-sequence aléatoire.\n", " - **Remplacement** : elitisme (garder les meilleurs).\n", "\n", - "**Pourquoi 0.07 s** : la complexite est O(n_generations · taille_population · N). Pour 100 generations et 50 individus = 5 000 evaluations -- rapide.\n", + "**Pourquoi 0.07 s** : la complexité est O(n_generations · taille_population · N). Pour 100 generations et 50 individus = 5 000 évaluations -- rapide.\n", "\n", - "**Sortie observee de code[7] -- visualisation** : la cellule inclut la tournee finale GA visualisee (cout 500.12). Le resultat est moins bon que SA (386.43) sur TSP-20, ce qui reflete que GA necessite des populations plus grandes pour converger.\n", + "**Sortie observee de code[7] -- visualisation** : la cellule inclut la tournee finale GA visualisee (coût 500.12). Le résultat est moins bon que SA (386.43) sur TSP-20, ce qui reflete que GA necessite des populations plus grandes pour converger.\n", "\n", - "**Note pedagogique** : GA est robuste aux paysages non-convexes mais exige une population suffisante pour explorer. Sur cette instance a 20 villes, SA est plus efficace. Sur TSP-50+, GA peut l'emporter en parallele." + "**Note pédagogique** : GA est robuste aux paysages non-convexes mais exige une population suffisante pour explorer. Sur cette instance a 20 villes, SA est plus efficace. Sur TSP-50+, GA peut l'emporter en parallele." ] }, { @@ -1122,13 +1122,13 @@ "\n", "Algorithme bio-inspire base sur le comportement collectif de fourmis qui deposent des pheromones sur leur chemin.\n", "\n", - "**Caracteristiques de ACO** :\n", - "- **Complexite temporelle** : O(n_iterations · n_fourmis · N).\n", + "**Caractéristiques de ACO** :\n", + "- **Complexité temporelle** : O(n_iterations · n_fourmis · N).\n", "- **Gap typique** : 2-5 % au-dessus de l'optimal avec un bon reglage.\n", - "- **Parametrage** : `n_fourmis`, `n_iterations`, `alpha` (poids pheromone), `beta` (poids distance), `evaporation` -- 5 hyperparametres.\n", + "- **Parametrage** : `n_fourmis`, `n_iterations`, `alpha` (poids pheromone), `beta` (poids distance), `evaporation` -- 5 hyperparamètres.\n", "\n", "**Intuition biologique** :\n", - "- **Alpha > 0** : les fourmis suivent preferentiellement les aretes deja frequentes (exploitation).\n", + "- **Alpha > 0** : les fourmis suivent preferentiellement les aretes déjà frequentes (exploitation).\n", "- **Beta > 0** : les fourmis preferent les aretes courtes (heuristique).\n", "- **Evaporation** : evite la convergence prematuree vers un optimum local." ] @@ -1284,15 +1284,15 @@ "source": [ "**Sortie observee de code[8]** (verbatim, instance TSP-20) : `Solution ACO: 386.63 / Temps: 0.77s`. La cellule implemente `colonie_fourmis(tsp, n_fourmis, n_iterations, alpha, beta, evaporation)` qui :\n", "- Initialise les pheromones a 0.1 sur toutes les aretes (`np.ones((n, n)) * 0.1`).\n", - "- A chaque iteration, chaque fourmi construit une tournee probabiliste : `P(arete) ∝ pheromone^alpha · (1/distance)^beta`.\n", - "- Mise a jour des pheromones : depot proportionnel a la qualite de la tournee, evaporation globale.\n", + "- A chaque itération, chaque fourmi construit une tournee probabiliste : `P(arete) ∝ pheromone^alpha · (1/distance)^beta`.\n", + "- Mise a jour des pheromones : dépôt proportionnel a la qualité de la tournee, evaporation globale.\n", "- Continue jusqu'a convergence.\n", "\n", - "**Pourquoi 0.77 s** : la complexite est O(n_iterations · n_fourmis · N). Pour 100 iterations et 20 fourmis = 2 000 evaluations -- comparable a GA.\n", + "**Pourquoi 0.77 s** : la complexité est O(n_iterations · n_fourmis · N). Pour 100 itérations et 20 fourmis = 2 000 évaluations -- comparable a GA.\n", "\n", - "**Sortie observee de code[8] -- visualisation** : la cellule inclut la tournee ACO finale (cout 386.63 -- identique a NN + 2-opt). C'est typique : ACO converge rapidement vers une bonne solution sur TSP-20.\n", + "**Sortie observee de code[8] -- visualisation** : la cellule inclut la tournee ACO finale (coût 386.63 -- identique a NN + 2-opt). C'est typique : ACO converge rapidement vers une bonne solution sur TSP-20.\n", "\n", - "**Note pedagogique** : ACO brille sur les problemes dynamiques (les pheromones s'adaptent en temps reel) et les variantes avec contraintes (STSP, TSPTW). Sur TSP statique symetrique, SA et 2-opt+ sont generalement competitifs." + "**Note pédagogique** : ACO brille sur les problèmes dynamiques (les pheromones s'adaptent en temps réel) et les variantes avec contraintes (STSP, TSPTW). Sur TSP statique symetrique, SA et 2-opt+ sont généralement compétitifs." ] }, { @@ -1311,12 +1311,12 @@ "source": [ "## 9. Benchmark Comparatif\n", "\n", - "Comparons toutes les methodes sur une instance de taille N=30 pour evaluer leurs performances relatives.\n", + "Comparons toutes les méthodes sur une instance de taille N=30 pour evaluer leurs performances relatives.\n", "\n", "**Structure du benchmark** :\n", - "- **Instance** : TSP-30 (30 villes aleatoires dans [0, 100]^2, graine 123).\n", - "- **Methodes** : NN, NN + 2-opt, SA, GA, ACO (5 methodes).\n", - "- **Metriques** : cout final, temps d'execution, et qualite = cout / meilleur cout des cinq methodes (la comparaison a OR-Tools est a la section 10)." + "- **Instance** : TSP-30 (30 villes aléatoires dans [0, 100]^2, graine 123).\n", + "- **Méthodes** : NN, NN + 2-opt, SA, GA, ACO (5 méthodes).\n", + "- **Metriques** : coût final, temps d'exécution, et qualité = coût / meilleur coût des cinq méthodes (la comparaison a OR-Tools est a la section 10)." ] }, { @@ -1416,11 +1416,11 @@ "id": "19f186f3", "metadata": {}, "source": [ - "**Sortie observee de code[9]** (verbatim) : la cellule imprime un tableau (Methode, Cout, Temps (s), Qualite) pour NN, NN+2-opt, SA, GA, ACO. L'instance TSP-30 est generee avec la graine 123 pour la reproductibilite.\n", + "**Sortie observee de code[9]** (verbatim) : la cellule imprime un tableau (Méthode, Coût, Temps (s), Qualité) pour NN, NN+2-opt, SA, GA, ACO. L'instance TSP-30 est generee avec la graine 123 pour la reproductibilite.\n", "\n", - "**Resultats mesures** (sortie committee, TSP-30) :\n", + "**Résultats mesures** (sortie committee, TSP-30) :\n", "\n", - "| Methode | Cout | Temps (s) | Qualite |\n", + "| Méthode | Coût | Temps (s) | Qualité |\n", "|---|---:|---:|---:|\n", "| NN | 494.69 | 0.000 | 1.04x |\n", "| NN+2opt | 489.74 | 0.007 | 1.03x |\n", @@ -1428,9 +1428,9 @@ "| GA | 732.23 | 0.030 | 1.55x |\n", "| ACO | 473.68 | 0.630 | 1.00x |\n", "\n", - "**Note pedagogique** : les methodes ne sont pas interchangeables : chacune a un domaine de predilection (NN rapide, 2-opt equilibre, SA/ACO pour la qualite, GA pour les paysages non-convexes). L'etudiant apprend a choisir la methode adaptee au contexte. Sur cette instance, l'ecart est net : GA est a 1.55x du meilleur, les autres methodes entre 1.00x et 1.04x.\n", + "**Note pédagogique** : les méthodes ne sont pas interchangeables : chacune a un domaine de predilection (NN rapide, 2-opt equilibre, SA/ACO pour la qualité, GA pour les paysages non-convexes). L'etudiant apprend a choisir la méthode adaptee au contexte. Sur cette instance, l'ecart est net : GA est a 1.55x du meilleur, les autres méthodes entre 1.00x et 1.04x.\n", "\n", - "**Limite honnete** : ce benchmark ne porte que sur une instance (TSP-30, graine 123) et une execution par methode ; l'ecart entre methodes n'est pas une moyenne sur plusieurs graines.\n", + "**Limite honnete** : ce benchmark ne porte que sur une instance (TSP-30, graine 123) et une exécution par méthode ; l'ecart entre méthodes n'est pas une moyenne sur plusieurs graines.\n", "\n", "Visualisation des résultats." ] @@ -1512,15 +1512,15 @@ "source": [ "### Lecture du benchmark comparatif (ancre sur code[10])\n", "\n", - "La sortie verbatim de code[10] est `
` -- une figure matplotlib avec 2 sous-graphiques comparant les 5 methodes sur TSP-30 (valeurs de la sortie de code[9]).\n", + "La sortie verbatim de code[10] est `
` -- une figure matplotlib avec 2 sous-graphiques comparant les 5 méthodes sur TSP-30 (valeurs de la sortie de code[9]).\n", "\n", - "**Sous-graphique gauche** : bar chart du cout final par methode. Le meilleur cout est celui d'ACO (473.68) ; GA (732.23) se detache nettement.\n", + "**Sous-graphique gauche** : bar chart du coût final par méthode. Le meilleur coût est celui d'ACO (473.68) ; GA (732.23) se detache nettement.\n", "\n", - "**Sous-graphique droite** : bar chart du temps d'execution, en echelle lineaire. Les temps de la sortie de code[9] sont : NN 0.000 s, NN + 2-opt 0.007 s, SA 1.262 s, GA 0.030 s, ACO 0.630 s.\n", + "**Sous-graphique droite** : bar chart du temps d'exécution, en echelle lineaire. Les temps de la sortie de code[9] sont : NN 0.000 s, NN + 2-opt 0.007 s, SA 1.262 s, GA 0.030 s, ACO 0.630 s.\n", "\n", - "**Lecture transversale** : il y a un **trade-off qualite/temps**. NN est le plus rapide mais peu precis (1.04x). SA et ACO sont les plus precis (1.01x et 1.00x) et prennent respectivement 1.262 s et 0.630 s. GA est rapide mais le plus eloigne du meilleur cout sur cette instance (1.55x) : le choix depend du budget temps et de la qualite visee.\n", + "**Lecture transversale** : il y a un **trade-off qualité/temps**. NN est le plus rapide mais peu précis (1.04x). SA et ACO sont les plus précis (1.01x et 1.00x) et prennent respectivement 1.262 s et 0.630 s. GA est rapide mais le plus eloigne du meilleur coût sur cette instance (1.55x) : le choix depend du budget temps et de la qualité visee.\n", "\n", - "**Note pedagogique** : sur ce benchmark, les methodes se distinguent par leur cout comme par leur temps ; ce carnet ne mesure pas ces ecarts sur d'autres tailles d'instance." + "**Note pédagogique** : sur ce benchmark, les méthodes se distinguent par leur coût comme par leur temps ; ce carnet ne mesure pas ces ecarts sur d'autres tailles d'instance." ] }, { @@ -1539,7 +1539,7 @@ "source": [ "## 10. Comparaison avec OR-Tools\n", "\n", - "Google OR-Tools fournit un solveur de routage generique. C'est la **reference industrielle** du carnet, appliquee ici a la meme instance TSP-30 que le benchmark (section 9)." + "Google OR-Tools fournit un solveur de routage generique. C'est la **reference industrielle** du carnet, appliquee ici a la même instance TSP-30 que le benchmark (section 9)." ] }, { @@ -1644,21 +1644,21 @@ "id": "5eec3599", "metadata": {}, "source": [ - "**Sortie observee de code[11]** (verbatim, instance TSP-30) : `Solution OR-Tools: 465.53 / Temps: 2.01s / Gap vs meilleure metaheuristique: 0.9828x`. La cellule utilise `ortools.constraint_solver.routing` pour resoudre l'instance.\n", + "**Sortie observee de code[11]** (verbatim, instance TSP-30) : `Solution OR-Tools: 465.53 / Temps: 2.01s / Gap vs meilleure metaheuristique: 0.9828x`. La cellule utilise `ortools.constraint_solver.routing` pour résoudre l'instance.\n", "\n", "**Pourquoi 2.01 s** : la recherche est bornee par `time_limit.seconds = 2` (`code[11]`). OR-Tools part d'une solution `PATH_CHEAPEST_ARC`, puis l'ameliore par recherche locale guidee (`GUIDED_LOCAL_SEARCH`). Le carnet ne mesure pas l'ecart a l'optimum de cette solution : OR-Tools n'est pas ici prouve optimal.\n", "\n", - "**Caracteristiques d'OR-Tools** :\n", + "**Caractéristiques d'OR-Tools** :\n", "- **Algorithme** : construction (`PATH_CHEAPEST_ARC`) puis recherche locale guidee (`GUIDED_LOCAL_SEARCH`).\n", - "- **Complexite** : configurable (limite de temps).\n", - "- **Gap typique** : ordre de grandeur de la litterature, non mesure dans ce carnet.\n", - "- **Cout** : 2.01 s sur TSP-30 (limite de 2 s).\n", + "- **Complexité** : configurable (limite de temps).\n", + "- **Gap typique** : ordre de grandeur de la littérature, non mesure dans ce carnet.\n", + "- **Coût** : 2.01 s sur TSP-30 (limite de 2 s).\n", "\n", - "**Sortie observee de code[11] -- visualisation** : la cellule inclut la tournee OR-Tools visualisee (cout 465.53, comparable aux methodes heuristiques).\n", + "**Sortie observee de code[11] -- visualisation** : la cellule inclut la tournee OR-Tools visualisee (coût 465.53, comparable aux méthodes heuristiques).\n", "\n", - "**Note d'arbitrage OR-Tools vs methodes maison** : sur TSP-30, OR-Tools (465.53) est meilleur que les cinq methodes du benchmark, dont la meilleure est ACO (473.68). Cette comparaison ne porte que sur cette instance, avec un seul essai par methode (limite de 2 s pour OR-Tools).\n", + "**Note d'arbitrage OR-Tools vs méthodes maison** : sur TSP-30, OR-Tools (465.53) est meilleur que les cinq méthodes du benchmark, dont la meilleure est ACO (473.68). Cette comparaison ne porte que sur cette instance, avec un seul essai par méthode (limite de 2 s pour OR-Tools).\n", "\n", - "**Implication pedagogique** : sur TSP-30, quatre methodes sur cinq restent a 1.06x de OR-Tools au plus (voir le tableau de synthese). Avec le critere du carnet (ecart < 5 %), SA et ACO passent ; 2-opt (1.05x) est juste au-dessus, NN et GA restent au-dela. Ce critere est une convention pedagogique, pas une garantie." + "**Implication pédagogique** : sur TSP-30, quatre méthodes sur cinq restent a 1.06x de OR-Tools au plus (voir le tableau de synthese). Avec le critere du carnet (ecart < 5 %), SA et ACO passent ; 2-opt (1.05x) est juste au-dessus, NN et GA restent au-dela. Ce critere est une convention pédagogique, pas une garantie." ] }, { @@ -1679,7 +1679,7 @@ "\n", "### Exercice 1 : Heuristique d'Insertion la Moins Chere\n", "\n", - "Implementez l'heuristique **Cheapest Insertion** qui construit une tournee en inserant chaque ville a la position qui augmente le moins le cout total.\n", + "Implementez l'heuristique **Cheapest Insertion** qui construit une tournee en inserant chaque ville a la position qui augmente le moins le coût total.\n", "\n", "**Indices** :\n", "- Commencez avec une tournee de 3 villes formant un triangle\n", @@ -1839,7 +1839,7 @@ "source": [ "### Exercice 2 : Opérateur de Voisinage Or-opt\n", "\n", - "L'opérateur **Or-opt** consiste a deplacer un segment de 1 a 3 villes consecutives a une autre position de la tournee. Implementez cet opérateur.\n", + "L'opérateur **Or-opt** consiste a déplacer un segment de 1 a 3 villes consecutives a une autre position de la tournee. Implementez cet opérateur.\n", "\n", "**Indices** :\n", "- Extrayez un segment de k villes (k = 1, 2 ou 3)\n", @@ -2001,7 +2001,7 @@ "source": [ "### Exercice 3 : Parametrisation du Recuit Simule (Reflexion)\n", "\n", - "Analysez l'impact des paramètres du recuit simule sur la qualite de la solution.\n", + "Analysez l'impact des paramètres du recuit simule sur la qualité de la solution.\n", "\n", "**Questions a considerer** :\n", "- Comment la temperature initiale (T0) affecte-t-elle l'exploration vs l'exploitation ?\n", @@ -2066,7 +2066,7 @@ "\n", "### Exemple : Hybridation GA + 2-opt\n", "\n", - "Combinaison de l'algorithme génétique avec une amelioration locale 2-opt appliquee a chaque enfant après crossover. Cette approche hybride exploite la capacite d'exploration du GA et le pouvoir d'intensification du 2-opt." + "Combinaison de l'algorithme génétique avec une amelioration locale 2-opt appliquee a chaque enfant après crossover. Cette approche hybride exploite la capacité d'exploration du GA et le pouvoir d'intensification du 2-opt." ] }, { @@ -2244,9 +2244,9 @@ "source": [ "### Interpretation Bonus 2\n", "\n", - "Sur notre test (TSP-40, graine 2027), le cout affiche pour 3-opt (632.87) est **identique au cout initial NN** : `three_opt` est un **stub d'exercice** (`# TODO etudiant`) qui retourne le tour sans le modifier. Le cout \"3-opt\" ne reflete donc pas une vraie amelioration 3-opt a comparer au 2-opt (553.98).\n", + "Sur notre test (TSP-40, graine 2027), le coût affiche pour 3-opt (632.87) est **identique au coût initial NN** : `three_opt` est un **stub d'exercice** (`# TODO etudiant`) qui retourne le tour sans le modifier. Le coût \"3-opt\" ne reflete donc pas une vraie amelioration 3-opt a comparer au 2-opt (553.98).\n", "\n", - "**A vous de jouer** : completez `three_opt` (test des rearrangements de 3 aretes, complexite $O(n^3)$) et re-executez cette cellule pour comparer honnetement 3-opt vs 2-opt. La litterature indique que 3-opt produit généralement une solution au moins aussi bonne que 2-opt, au prix d'un cout de calcul plus eleve." + "**A vous de jouer** : completez `three_opt` (test des rearrangements de 3 aretes, complexité $O(n^3)$) et re-executez cette cellule pour comparer honnetement 3-opt vs 2-opt. La littérature indique que 3-opt produit généralement une solution au moins aussi bonne que 2-opt, au prix d'un coût de calcul plus eleve." ] }, { @@ -2477,7 +2477,7 @@ "### Exercice 4 : Recherche Tabou (Tabu Search)\n", "\n", "La **recherche tabou** (Glover, 1986) est une métaheuristique déterministe qui utilise une\n", - "memoire a court terme pour eviter de revisiter des solutions déjà explorees.\n", + "memoire a court terme pour éviter de revisiter des solutions déjà explorees.\n", "\n", "**Principe** :\n", "1. Partez d'une solution initiale et explorez son voisinage (echange de 2 villes)\n", @@ -2486,8 +2486,8 @@ "4. **Critere d'aspiration** : un mouvement tabou est accepte s'il produit un nouveau global best\n", "5. Repetez pendant un nombre fixe d'itérations\n", "\n", - "**Paramètres cles** :\n", - "- `tabu_tenure` : duree d'interdiction d'un mouvement (typique : n/3 a n)\n", + "**Paramètres clés** :\n", + "- `tabu_tenure` : durée d'interdiction d'un mouvement (typique : n/3 a n)\n", "- `max_iter` : budget d'itérations total\n", "- `aspiration` : activer le critere de nouveau global best\n", "\n", @@ -2694,9 +2694,9 @@ "\n", "**Observations** :\n", "\n", - "1. **Monotonie du meilleur global** : La courbe du meilleur cout global est decroissante\n", + "1. **Monotonie du meilleur global** : La courbe du meilleur coût global est decroissante\n", " par construction -- la recherche tabou ne met a jour le meilleur global que lorsqu'une\n", - " amelioration est trouvee. Le cout actuel peut remonter (acceptation du meilleur voisin\n", + " amelioration est trouvee. Le coût actuel peut remonter (acceptation du meilleur voisin\n", " même degradant), mais le meilleur enregistre ne fait que descendre.\n", "\n", "2. **Petites instances (n <= 15)** : Tabou et SA trouvent souvent la même solution optimale\n", @@ -2708,7 +2708,7 @@ " si le voisinage est mal explore, elle peut stagner.\n", "\n", "4. **Quand privilegier la recherche tabou** :\n", - " - Quand la reproductibilite est importante (pas d'aleatoire dans le choix du voisin)\n", + " - Quand la reproductibilite est importante (pas d'aléatoire dans le choix du voisin)\n", " - Quand le voisinage est structure et que la memoire tabou empeche efficacement le cyclage\n", " - Quand on veut un comportement déterministe pour des tests de regression\n", "\n", @@ -2735,34 +2735,34 @@ "\n", "### Tableau comparatif\n", "\n", - "| Methode | Complexite | Gap typique | Parametrage | Cas d'usage |\n", + "| Méthode | Complexité | Gap typique | Parametrage | Cas d'usage |\n", "|---------|-----------|-------------|-------------|-------------|\n", "| Force brute | O(N!) | 0 % | aucun | Reference, N <= 12 |\n", - "| NN | O(N^2) | 20-30 % | depart | Baseline rapide |\n", + "| NN | O(N^2) | 20-30 % | départ | Baseline rapide |\n", "| 2-opt | O(N^2 · iter) | 5-10 % | max_iter | Amelioration NN |\n", - "| SA | O(n_iter · N) | 2-5 % | T_init, T_fin, n_iter | Metaheuristique equilibree |\n", + "| SA | O(n_iter · N) | 2-5 % | T_init, T_fin, n_iter | Métaheuristique equilibree |\n", "| GA | O(n_gen · pop · N) | 10-20 % | pop, n_gen, taux | Paysages non-convexes |\n", - "| ACO | O(n_iter · n_fourmis · N) | 2-5 % | n_fourmis, alpha, beta | Problemes dynamiques |\n", + "| ACO | O(n_iter · n_fourmis · N) | 2-5 % | n_fourmis, alpha, beta | Problèmes dynamiques |\n", "| OR-Tools | configurable | < 2 % | timeout | Production, N <= 1000 |\n", "\n", "### Recommandations par taille d'instance\n", "\n", "- **N <= 12** : force brute (optimal garanti, temps negligeable).\n", "- **N = 10-50** : NN + 2-opt (rapide, bon gap).\n", - "- **N = 50-200** : SA ou ACO (bon equilibre qualite/temps).\n", + "- **N = 50-200** : SA ou ACO (bon equilibre qualité/temps).\n", "- **N = 200-1000** : OR-Tools ou LK-H.\n", "- **N > 1000** : solveurs specialises (Concorde, branch-and-bound parallele).\n", "\n", - "### Taxonomie des methodes et critere de choix\n", + "### Taxonomie des méthodes et critere de choix\n", "\n", "Le TSP illustre la **diversite des approches d'optimisation combinatoire** :\n", - "1. **Methodes exactes** : explosion exponentielle, cas de petite taille.\n", + "1. **Méthodes exactes** : explosion exponentielle, cas de petite taille.\n", "2. **Heuristiques constructives** : rapides, gap eleve.\n", - "3. **Recherche locale** : equilibre qualite/temps, gap modere.\n", - "4. **Metaheuristiques** : robustes, gap faible, temps plus long.\n", - "5. **Solveurs industriels** : optimisation adaptee, gap tres faible.\n", + "3. **Recherche locale** : equilibre qualité/temps, gap modere.\n", + "4. **Métaheuristiques** : robustes, gap faible, temps plus long.\n", + "5. **Solveurs industriels** : optimisation adaptee, gap très faible.\n", "\n", - "Le choix de la methode depend du contexte (taille, budget temps, qualite requise)." + "Le choix de la méthode depend du contexte (taille, budget temps, qualité requise)." ] }, { @@ -2801,7 +2801,7 @@ "\n", "L'algorithme génétique seul est le plus faible (1.57x la référence OR-Tools sur TSP-30), mais **combine avec 2-opt, il passe de 930.98 a 520.23** (TSP-40, `code[19]`), soit une amelioration de 44.12 %. Le 2-opt est le post-traitement universel qui ameliore systematiquement toute solution. OR-Tools reste la reference de production.\n", "\n", - "Le TSP illustre le compromis fondamental : les méthodes exactes garantissent l'optimalite mais explosent au-dela de n~10-12 villes, tandis que les métaheuristiques scalent mais sans garantie.\n", + "Le TSP illustre le compromis fondamental : les méthodes exactes garantissent l'optimalité mais explosent au-dela de n~10-12 villes, tandis que les métaheuristiques scalent mais sans garantie.\n", "\n", "**Navigation** : [<< Portfolio](App-10-Portfolio.ipynb) | [App-14 - Connect Four adversarial](App-14-ConnectFour-Adversarial.ipynb) | [Retour au sommaire](../README.md)" ] @@ -2859,4 +2859,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-14-ConnectFour-Adversarial.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-14-ConnectFour-Adversarial.ipynb index be12cd93e75..97e66aa2bdf 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-14-ConnectFour-Adversarial.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-14-ConnectFour-Adversarial.ipynb @@ -22,16 +22,16 @@ "\n", "A la fin de ce notebook, vous saurez :\n", "1. **Comparer** les algorithmes Minimax, Alpha-Beta et MCTS sur un jeu réel\n", - "2. **mesurer** les compromis entre temps de calcul, noeuds explores et qualite de jeu\n", + "2. **mesurer** les compromis entre temps de calcul, noeuds explores et qualité de jeu\n", "3. **Analyser** l'impact de la profondeur de recherche et du nombre d'itérations\n", "4. **Choisir** l'algorithme adapté selon les contraintes (temps, precision)\n", "\n", - "### Prerequis\n", + "### Prérequis\n", "- [Search-03-Informed](../Part1-Foundations/Search-03-Informed.ipynb) : Heuristiques\n", "- [Search-06-AdversarialSearch](../Part1-Foundations/Search-06-AdversarialSearch.ipynb) : Minimax, Alpha-Beta\n", "- [Search-07-MCTS-And-Beyond](../Part1-Foundations/Search-07-MCTS-And-Beyond.ipynb) : MCTS (recommande)\n", "\n", - "### Duree estimee : 45 minutes\n", + "### Durée estimee : 45 minutes\n", "\n", "> **Source** : adapté des projets etudiants JVX (ECE 2026) et EPITA PPC 2025.\n", ">\n", @@ -64,21 +64,21 @@ "\n", "Repertoire source : [jsboigeEpita/2025-Epita-Programmation-par-Contraintes/tree/main/Groupe_12 _Puissance_4](https://github.com/jsboigeEpita/2025-Epita-Programmation-par-Contraintes/tree/main/Groupe_12%20_Puissance_4), commit principal `9c7e5ba` (merge par `jsboige`), licence **MIT** (`Copyright (c) 2025 jsboigeEpita`, fichier LICENSE dans le sous-projet, verifie firsthand 2026-09-17 via `https://raw.githubusercontent.com/.../LICENSE`).\n", "\n", - "Le projet EPITA PPC 2025 couvre deja l'essentiel de ce que ce notebook reprend :\n", + "Le projet EPITA PPC 2025 couvre déjà l'essentiel de ce que ce notebook reprend :\n", "\n", - "- l'**implementation du moteur de jeu** Puissance 4 (regles, detection de victoire, representation du plateau) ;\n", - "- la **comparaison Minimax vs Alpha-Beta vs MCTS** sur le meme terrain.\n", + "- l'**implementation du moteur de jeu** Puissance 4 (règles, detection de victoire, représentation du plateau) ;\n", + "- la **comparaison Minimax vs Alpha-Beta vs MCTS** sur le même terrain.\n", "\n", "Ce qui est *ajoute* dans ce notebook :\n", "\n", - "1. la **couche benchmark rigoureuse** (Section 4) avec mesures de noeuds explores, temps, et qualite de jeu sur instances parametrees ;\n", - "2. la **discussion approfondie des compromis** (Section 5) entre profondeur et temps -- le projet source livre des implementations, pas une etude comparative formelle ;\n", + "1. la **couche benchmark rigoureuse** (Section 4) avec mesures de noeuds explores, temps, et qualité de jeu sur instances parametrees ;\n", + "2. la **discussion approfondie des compromis** (Section 5) entre profondeur et temps -- le projet source livre des implementations, pas une étude comparative formelle ;\n", "3. la **visualisation** des arbres de recherche (Section 6) qui rend visible l'elagage Alpha-Beta ;\n", "4. les **trois exercices** sur les variations realistes (profondeur iterative, iterative deepening, parallelisation).\n", "\n", "L'enrichissement preserve les implementations du moteur et des algorithmes ; les ajouts sont concentres sur la *couche experimentale et comparative*.\n", "\n", - "**Note** : ce notebook se concentre sur le benchmark des trois algorithmes principaux. Pour une etude complete -- aleatoire, glouton, Minimax alpha-beta, MCTS, framework AIMA de Russell & Norvig, approfondissement iteratif et Negamax --, voir [App-12b](App-12b-ConnectFour.ipynb).\n", + "**Note** : ce notebook se concentre sur le benchmark des trois algorithmes principaux. Pour une étude complete -- aléatoire, glouton, Minimax alpha-beta, MCTS, framework AIMA de Russell & Norvig, approfondissement iteratif et Negamax --, voir [App-12b](App-12b-ConnectFour.ipynb).\n", "\n" ] }, @@ -107,7 +107,7 @@ "| Taille du plateau | 7x6 = 42 cases | Assez grand pour etre intéressant |\n", "| Facteur de branchement | ~4-7 | Teste l'efficacité de l'elagage |\n", "| Profondeur moyenne | ~21 coups | suffisant pour mesurer les performances |\n", - "| Jeu résolu | Oui (1988) | Permet de vérifier l'optimalite |\n", + "| Jeu résolu | Oui (1988) | Permet de vérifier l'optimalité |\n", "\n", "### Les trois algorithmes compares\n", "\n", @@ -119,7 +119,7 @@ "\n", "- Quel algorithme est le plus rapide ?\n", "- Lequel joue le mieux avec un temps limite ?\n", - "- Comment la profondeur affecte-t-elle la qualite ?" + "- Comment la profondeur affecte-t-elle la qualité ?" ] }, { @@ -464,7 +464,7 @@ "0 1 2 3 4 5 6\n", "```\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Gravite correcte** : Les jetons tombent jusqu'au premier emplacement vide\n", "2. **Alternance respectee** : MAX et MIN alternent correctement\n", "3. **détection victoire** : Aucun alignement de 4 (correct)\n", @@ -497,7 +497,7 @@ "\n", "### Fonction d'évaluation\n", "\n", - "Pour les etats non terminaux, nous utilisons une heuristique basee sur :\n", + "Pour les états non terminaux, nous utilisons une heuristique basee sur :\n", "- Le contrôle du centre\n", "- Le nombre de \"fenêtrès\" gagnantes potentielles" ] @@ -657,7 +657,7 @@ "0 1 2 3 4 5 6\n", "```\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Avantage MAX** : Score 9 vs 3 = MAX a un net avantage\n", "2. **Contrôle du centre** : Les 2 jetons X au centre (colonnes 3-4) sont valorises\n", "3. **Bonus centre** : La colonne 3 a 1 jeton X = bonus de 3 points\n", @@ -819,20 +819,20 @@ "\n", "**Sortie obtenue** : Minimax avec profondeur 4 sur position initiale.\n", "\n", - "| Metrique | Valeur | Signification |\n", + "| Métrique | Valeur | Signification |\n", "|----------|--------|---------------|\n", "| Meilleur coup | 3 (colonne centrale) | Contrôle du centre = stratégie optimale |\n", "| Valeur | 6.00 | Score heuristique positif (avantage MAX) |\n", - "| Noeuds explores | 2,801 | Explosion combinatoire : ~7^4 = 2401 theoriques |\n", + "| Noeuds explores | 2,801 | Explosion combinatoire : ~7^4 = 2401 théoriques |\n", "| Temps | Runtime *machine-dep* | Performance typique pour d=4 (CPython + numpy) |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Coup optimal** : Colonne 3 (centre) est le meilleur premier coup\n", - "2. **Complexite** : 2,801 noeuds pour seulement 4 profondeurs\n", + "2. **Complexité** : 2,801 noeuds pour seulement 4 profondeurs\n", "3. **Heuristique efficace** : Score 6.00 = avantage modere pour MAX\n", "4. **Scalabilite** : les benchmarks ulterieurs (cellule suivante) montrent que d>5 devient prohibitif (croissance b^d)\n", "\n", - "> **Note technique** : Le **nombre de noeuds** (2,801) est un invariant structurel du probleme sur cette instance (deterministe sur la profondeur et la position initiale) : il est **superieur a b^d = 7^4 = 2,401** car (1) le facteur de branchement diminue en profondeur (colonnes se remplissent), (2) certaines branches sont plus longues que d=4, (3) l'exploration continue meme quand le plateau est presque plein. Minimax explore systematiquement TOUTES les branches jusqu'a la profondeur d, sans aucun elagage. C'est son principal defaut. Le **temps d'execution** est en revanche machine-dep (CPython + charge systeme + taille instance) ; il **ne survit pas** a une re-execution sur une autre machine. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note technique** : Le **nombre de noeuds** (2,801) est un invariant structurel du problème sur cette instance (déterministe sur la profondeur et la position initiale) : il est **superieur a b^d = 7^4 = 2,401** car (1) le facteur de branchement diminue en profondeur (colonnes se remplissent), (2) certaines branches sont plus longues que d=4, (3) l'exploration continue même quand le plateau est presque plein. Minimax explore systematiquement TOUTES les branches jusqu'a la profondeur d, sans aucun elagage. C'est son principal defaut. Le **temps d'exécution** est en revanche machine-dep (CPython + charge système + taille instance) ; il **ne survit pas** a une re-exécution sur une autre machine. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n" ] }, @@ -1004,19 +1004,19 @@ "\n", "**Sortie obtenue** : Alpha-Beta avec profondeur 4 sur position initiale.\n", "\n", - "| Metrique | Valeur | Comparaison vs Minimax |\n", + "| Métrique | Valeur | Comparaison vs Minimax |\n", "|----------|--------|----------------------|\n", "| Meilleur coup | 3 | Identique (centre) |\n", "| Valeur | 6.00 | Identique (optimal) |\n", "| Noeuds explores | 178 | **15.7x moins** (invariant structurel) |\n", "| Temps | Runtime *machine-dep* | Speedup wall-clock *machine-dep* (Minimax / Alpha-Beta) |\n", "\n", - "**Points cles** :\n", - "1. **résultat identique** : meme coup (colonne 3) et meme valeur (6.00)\n", + "**Points clés** :\n", + "1. **résultat identique** : même coup (colonne 3) et même valeur (6.00)\n", "2. **Elagage massif** : 178 noeuds vs 2,801 = 94% de reduction (invariant structurel)\n", - "3. **Optimalite gardee** : Alpha-Beta ne change pas le resultat, seulement le cout de la recherche\n", + "3. **Optimalité gardee** : Alpha-Beta ne change pas le résultat, seulement le coût de la recherche\n", "\n", - "> **Note technique** : La **reduction de 15.7x en noeuds** a profondeur 4 est un invariant structurel de l'elagage Alpha-Beta sur cette instance (deterministe, propriete algorithmique). Elle est excellente mais loin du maximum theorique b^(d/2) = environ 7^2 = 49x de reduction. L'ordonnancement actuel (par proximite au centre) est heuristique mais non optimal. Pour ameliorer, on pourrait : (1) trier par valeur de l'iteration precedente, (2) utiliser une table de transposition, (3) ordonnancer par les coups les plus joues. Le **speedup wall-clock** (rapport des temps d'execution) est en revanche *machine-dep* et depend du CLR Python, de la charge systeme et de la taille de l'instance ; il **ne survit pas** a une re-execution sur une autre machine, meme si l'ordre de grandeur est preserve. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note technique** : La **reduction de 15.7x en noeuds** a profondeur 4 est un invariant structurel de l'elagage Alpha-Beta sur cette instance (déterministe, propriete algorithmique). Elle est excellente mais loin du maximum théorique b^(d/2) = environ 7^2 = 49x de reduction. L'ordonnancement actuel (par proximite au centre) est heuristique mais non optimal. Pour ameliorer, on pourrait : (1) trier par valeur de l'itération précédente, (2) utiliser une table de transposition, (3) ordonnancer par les coups les plus joues. Le **speedup wall-clock** (rapport des temps d'exécution) est en revanche *machine-dep* et depend du CLR Python, de la charge système et de la taille de l'instance ; il **ne survit pas** a une re-exécution sur une autre machine, même si l'ordre de grandeur est preserve. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n" ] }, @@ -1264,22 +1264,22 @@ "source": [ "### Interprétation : Test MCTS\n", "\n", - "**Sortie obtenue** : MCTS avec 1000 iterations sur position initiale (seed posé dans la cellule de test : sortie reproductible).\n", + "**Sortie obtenue** : MCTS avec 1000 itérations sur position initiale (seed posé dans la cellule de test : sortie reproductible).\n", "\n", - "| Metrique | Valeur | Analyse |\n", + "| Métrique | Valeur | Analyse |\n", "|----------|--------|---------|\n", "| Meilleur coup | 5 | Colonne périphérique -- le MCTS naïf à ce budget ne trouve pas le centre |\n", - "| Taux de victoire | 0.109 | Valeur faible et bruitée pour 1000 iterations (convention détaillée dans le benchmark, section 6) |\n", + "| Taux de victoire | 0.109 | Valeur faible et bruitée pour 1000 itérations (convention détaillée dans le benchmark, section 6) |\n", "| Noeuds explores | 2,000 | 1000 selections + 1000 simulations (invariant structurel sur ce budget) |\n", - "| Temps | Runtime *machine-dep* | Cout wall-clock pour 1000 iterations (CPython + numpy) |\n", + "| Temps | Runtime *machine-dep* | Coût wall-clock pour 1000 itérations (CPython + numpy) |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Pas de coup central** : contrairement à Minimax et Alpha-Beta, le MCTS à rollouts uniformes ne privilégie pas la colonne 3 à ce budget -- le signal des parties aléatoires est trop pauvre pour discriminer les colonnes sur Connect Four\n", - "2. **Taux de victoire modere** : 0.109, estimation bruitée pour 1000 iterations\n", - "3. **convergence lente** : MCTS nécessite beaucoup plus d'iterations (ou des rollout policies biaisées) pour affiner Connect Four -- le tournoi de la section suivante le confirme\n", + "2. **Taux de victoire modere** : 0.109, estimation bruitée pour 1000 itérations\n", + "3. **convergence lente** : MCTS nécessite beaucoup plus d'itérations (ou des rollout policies biaisées) pour affiner Connect Four -- le tournoi de la section suivante le confirme\n", "4. **Speedup wall-clock** : ratio MCTS/Alpha-Beta = *machine-dep* (CPython + numpy + budget 1000 iter)\n", "\n", - "> **Note technique** : MCTS est **probabiliste** : sans seed, chaque execution donne un resultat legerement different -- le seed posé dans la cellule de test rend cette sortie précise reproductible. Le **taux de victoire** estime reste faible car les rollouts aleatoires exploitent mal la structure tactique forte de Connect Four. Le **budget d'iterations** (1000) et le **nombre de noeuds explores** (2,000 = selections + simulations) sont des invariants structurels du budget de simulation (deterministes sur le budget) ; le **temps d'execution** est en revanche *machine-dep* (CPython + charge + 1000 iterations). MCTS brille sur les jeux a grand facteur de branchement (Go, Havannah) ou les rollouts explorent des espaces vastes. Pour Connect Four, Alpha-Beta avec une bonne heuristique est nettement superieur. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous." + "> **Note technique** : MCTS est **probabiliste** : sans seed, chaque exécution donne un résultat legerement différent -- le seed posé dans la cellule de test rend cette sortie précise reproductible. Le **taux de victoire** estime reste faible car les rollouts aléatoires exploitent mal la structure tactique forte de Connect Four. Le **budget d'itérations** (1000) et le **nombre de noeuds explores** (2,000 = selections + simulations) sont des invariants structurels du budget de simulation (déterministes sur le budget) ; le **temps d'exécution** est en revanche *machine-dep* (CPython + charge + 1000 itérations). MCTS brille sur les jeux a grand facteur de branchement (Go, Havannah) ou les rollouts explorent des espaces vastes. Pour Connect Four, Alpha-Beta avec une bonne heuristique est nettement superieur. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous." ] }, { @@ -1301,7 +1301,7 @@ "Comparons les trois algorithmes sur différentes dimensions :\n", "- **Temps d'exécution**\n", "- **Noeuds explores**\n", - "- **Qualite du coup** (vs coup optimal)" + "- **Qualité du coup** (vs coup optimal)" ] }, { @@ -1515,13 +1515,13 @@ "| 5 | 19,608 | 641 | 30.6x | Runtime *machine-dep* | Runtime *machine-dep* | Speedup wall-clock *machine-dep* |\n", "| 6 | 137,257 | 1,370 | 100.2x | Runtime *machine-dep* | Runtime *machine-dep* | Speedup wall-clock *machine-dep* |\n", "\n", - "**Points cles** :\n", - "1. **Speedup noeuds exponentiel** : Le **speedup structurel** (rapport des **noeuds explores**, invariant algorithmique deterministe) augmente de 1x a 100x entre d=1 et d=6 — preuve que l'elagage Alpha-Beta est d'autant plus efficace que la profondeur augmente\n", - "2. **Complexite Minimax** : 137k noeuds a d=6 = explosion combinatoire (b^d avec b~4-7)\n", + "**Points clés** :\n", + "1. **Speedup noeuds exponentiel** : Le **speedup structurel** (rapport des **noeuds explores**, invariant algorithmique déterministe) augmente de 1x a 100x entre d=1 et d=6 — preuve que l'elagage Alpha-Beta est d'autant plus efficace que la profondeur augmente\n", + "2. **Complexité Minimax** : 137k noeuds a d=6 = explosion combinatoire (b^d avec b~4-7)\n", "3. **Efficacite Alpha-Beta** : Seulement 1.4k noeuds a d=6 = elagage massif (invariant structurel)\n", - "4. **Speedup temps wall-clock** : le **speedup runtime** (rapport des temps d'execution) depend du CLR Python, de la charge systeme et de la profondeur ; il **ne survit pas** a une re-execution\n", + "4. **Speedup temps wall-clock** : le **speedup runtime** (rapport des temps d'exécution) depend du CLR Python, de la charge système et de la profondeur ; il **ne survit pas** a une re-exécution\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : le theoreme dit qu'Alpha-Beta est O(b^(d/2)) avec ordonnancement optimal vs O(b^d) pour Minimax. Sur Connect Four 7x6, le **nombre de noeuds explores** (Minimax 137,257 / Alpha-Beta 1,370 a d=6) est un **invariant structurel** du probleme sur l'instance (deterministe, propriete algorithmique du recursive search sans randomness). En revanche, le **temps d'execution** et le **speedup wall-clock** dependent du CLR Python, de la charge systeme et de la taille de l'instance (ordres de grandeur typiques a d=6 : quelques dizaines de secondes pour Minimax contre une fraction de seconde pour Alpha-Beta -- mesures reelles dans la sortie du benchmark ci-dessus) -- ils **ne survivent pas** a une re-execution sur une autre machine, meme si l'ordre de grandeur est preserve. Les valeurs observees sur cette machine sont conformes au pattern theorique b^(d/2) ; pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note methodologique -- separation structurel / machine-dep** : le theoreme dit qu'Alpha-Beta est O(b^(d/2)) avec ordonnancement optimal vs O(b^d) pour Minimax. Sur Connect Four 7x6, le **nombre de noeuds explores** (Minimax 137,257 / Alpha-Beta 1,370 a d=6) est un **invariant structurel** du problème sur l'instance (déterministe, propriete algorithmique du récursive search sans randomness). En revanche, le **temps d'exécution** et le **speedup wall-clock** dependent du CLR Python, de la charge système et de la taille de l'instance (ordres de grandeur typiques a d=6 : quelques dizaines de secondes pour Minimax contre une fraction de seconde pour Alpha-Beta -- mesures reelles dans la sortie du benchmark ci-dessus) -- ils **ne survivent pas** a une re-exécution sur une autre machine, même si l'ordre de grandeur est preserve. Les valeurs observees sur cette machine sont conformes au pattern théorique b^(d/2) ; pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n" ] }, @@ -1712,19 +1712,19 @@ "**Sortie obtenue** : performance de MCTS sur la position initiale (plateau vide) avec différents nombres d'itérations (seed posé dans `run_benchmark_mcts` : table reproductible).\n", "\n", "**Lecture du tableau** :\n", - "- **Coup** : colonne choisie par MCTS comme meilleur premier coup pour le joueur 1. La théorie (Allis 1988) donne la colonne 3 (centre) comme optimale ; sur la sortie, les colonnes choisies restent erratiques sur toute la grille de budgets (0, 4, 6, 5, 0) -- voir « Points cles ».\n", - "- **Taux victoire** : ratio `wins/visites` au noeud du coup choisi a la racine. Deux conventions a lire avant d'interpreter la colonne : (1) la backpropagation alternée (`_backpropagate`) stocke au noeud enfant la valeur **du point de vue du joueur qui y joue** -- l'adversaire du joueur 1 -- et (2) cette valeur est **signee** (+1 victoire, 0 nul, -1 defaite). La colonne mesure donc l'estimation esperee de l'adversaire apres le coup choisi : les valeurs observees (+0.016 a +0.161) restent proches de zero -- l'adversaire n'a statistiquement ni avantage net ni desavantage net sous rollouts uniformes. Ce n'est PAS une probabilite de victoire du joueur 1.\n", + "- **Coup** : colonne choisie par MCTS comme meilleur premier coup pour le joueur 1. La théorie (Allis 1988) donne la colonne 3 (centre) comme optimale ; sur la sortie, les colonnes choisies restent erratiques sur toute la grille de budgets (0, 4, 6, 5, 0) -- voir « Points clés ».\n", + "- **Taux victoire** : ratio `wins/visites` au noeud du coup choisi a la racine. Deux conventions a lire avant d'interpreter la colonne : (1) la backpropagation alternée (`_backpropagate`) stocke au noeud enfant la valeur **du point de vue du joueur qui y joue** -- l'adversaire du joueur 1 -- et (2) cette valeur est **signee** (+1 victoire, 0 nul, -1 defaite). La colonne mesure donc l'estimation esperee de l'adversaire après le coup choisi : les valeurs observees (+0.016 a +0.161) restent proches de zero -- l'adversaire n'a statistiquement ni avantage net ni desavantage net sous rollouts uniformes. Ce n'est PAS une probabilite de victoire du joueur 1.\n", "- **Noeuds explores** : compteur cumule expansions + simulations. Pour `itérations=N`, on a typiquement ~2N (une expansion + une simulation par tour) -- exactement 2N sur chaque ligne de la sortie.\n", "- **Temps** : temps mur. Croît ~linéairement avec le nombre d'itérations (2,4 à 2,5 ms par itération sur ce run ; le dernier point, 12,6 s pour 5000 itérations, dévie légèrement au-dessus).\n", "\n", "**Ce que montre la sortie** :\n", - "1. **Pas de convergence vers le centre** : le coup choisi varie d'un budget a l'autre (0, 4, 6, 5, 0). Avec des rollouts uniformement aleatoires, le signal est trop pauvre pour discriminer les colonnes de Connect Four ; a ces budgets, MCTS se comporte proche d'un choix quasi aleatoire -- le tournoi de la section suivante le confirme (MCTS(1000) finit dernier).\n", + "1. **Pas de convergence vers le centre** : le coup choisi varie d'un budget a l'autre (0, 4, 6, 5, 0). Avec des rollouts uniformement aléatoires, le signal est trop pauvre pour discriminer les colonnes de Connect Four ; a ces budgets, MCTS se comporte proche d'un choix quasi aléatoire -- le tournoi de la section suivante le confirme (MCTS(1000) finit dernier).\n", "2. **Taux victoire faible, sans tendance** : +0.016 a +0.161 sur toute la grille, sans affinement net quand le budget monte -- coherent avec un signal de rollout pauvre, pas avec une estimation qui convergerait.\n", - "3. **Noeuds explores** : exactement 2 x iterations sur chaque ligne (200, 1000, 2000, 4000, 10000) -- l'invariant structurel du benchmark.\n", + "3. **Noeuds explores** : exactement 2 x itérations sur chaque ligne (200, 1000, 2000, 4000, 10000) -- l'invariant structurel du benchmark.\n", "\n", - "**Points cles** :\n", - "- **cohérence garantie** : grâce au reset d'etat dans `MCTS.search` (sauvegarde/restauration via `game.set_state(initial_state)`) et a la creation d'un `ConnectFour()` neuf par ligne dans `run_benchmark_mcts`, chaque ligne du tableau correspond bien a un benchmark sur la **même position de depart** (plateau vide). Sans ce reset, l'etat du jeu derivait entre itérations vers des positions arbitraires, faussant la comparaison.\n", - "- **MCTS est stochastique** : le seed posé dans `run_benchmark_mcts` rend la table reproductible d'une exécution a l'autre ; sans seed, coups et taux fluctuent a chaque re-execution (rollouts aléatoires).\n", + "**Points clés** :\n", + "- **cohérence garantie** : grâce au reset d'état dans `MCTS.search` (sauvegarde/restauration via `game.set_state(initial_state)`) et a la création d'un `ConnectFour()` neuf par ligne dans `run_benchmark_mcts`, chaque ligne du tableau correspond bien a un benchmark sur la **même position de départ** (plateau vide). Sans ce reset, l'état du jeu derivait entre itérations vers des positions arbitraires, faussant la comparaison.\n", + "- **MCTS est stochastique** : le seed posé dans `run_benchmark_mcts` rend la table reproductible d'une exécution a l'autre ; sans seed, coups et taux fluctuent a chaque re-exécution (rollouts aléatoires).\n", "- **Connect Four est résolu** : le joueur 1 gagne avec jeu parfait en commencant par la colonne 3 (Allis 1988). MCTS sans heuristique d'évaluation ne le découvre qu'avec beaucoup de rollouts -- la sortie ci-dessus en est l'illustration directe ; pour un agent réaliste sur Connect Four, on couplerait MCTS a un réseau de neurones (cf AlphaZero) ou on utiliserait Alpha-Beta avec table de transposition.\n", "\n", "> **Note technique** : les rollouts sont **uniformêment aléatoires** ici (cf `_simulate`). Cela donne un signal pauvre sur Connect Four ou la victoire dépend de patterns précis (4-en-ligne). Une amélioration classique consiste a biaiser les rollouts vers des coups gagnants/bloquants immédiats (heuristique de simulation), ou a remplacer la simulation par l'évaluation d'un réseau de neurones entraine." @@ -1841,16 +1841,16 @@ "|--------|-------------|---------------|\n", "| **Noeuds explores** | croissance exponentielle pour Minimax, lineaire pour Alpha-Beta (invariants structurels) | Elagage de plus en plus efficace avec la profondeur |\n", "| **Temps exécution** | Ecart runtime critique entre d=5 et d=6 (Minimax d=6 / Alpha-Beta d=6 -- speedup wall-clock *machine-dep*) | Runtime *machine-dep* depend du CLR Python + charge |\n", - "| **Speedup noeuds** | 1x (d=1) a 100x (d=6) -- invariant structurel deterministe | L'elagage augmente avec la profondeur |\n", - "| **échelle log** | necessaire pour visualiser la difference | difference de 2 ordres de grandeur |\n", + "| **Speedup noeuds** | 1x (d=1) a 100x (d=6) -- invariant structurel déterministe | L'elagage augmente avec la profondeur |\n", + "| **échelle log** | nécessaire pour visualiser la différence | différence de 2 ordres de grandeur |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Explosion combinatoire** : Minimax devient impraticable des d=6 (~runtime *machine-dep* sur cette machine)\n", "2. **Efficacite Alpha-Beta** : 100x moins de noeuds explores (invariant structurel), speedup wall-clock *machine-dep* a d=6\n", "3. **Seuil pratique** : Pour Connect Four, Alpha-Beta d=6-8 est realiste, Minimax d>5 ne l'est pas\n", - "4. **Ordre de grandeur** : L'echelle logarithmique masque la difference reelle (137k vs 1.4k noeuds, invariant structurel)\n", + "4. **Ordre de grandeur** : L'echelle logarithmique masque la différence reelle (137k vs 1.4k noeuds, invariant structurel)\n", "\n", - "> **Note technique** : Le **speedup structurel** (rapport des noeuds explores, 1x a 100x entre d=1 et d=6) augmente avec la profondeur car l'elagage a plus d'opportunites de couper des branches. A profondeur 1, aucun elagage n'est possible (toutes les feuilles sont au meme niveau). L'ordonnancement des coups (centre en priorite) maximise cet elagage. Le **speedup wall-clock** (rapport des temps d'execution, runtime *machine-dep* sur cette machine) suit le meme pattern mais avec une amplitude qui depend du CLR Python, de la charge systeme et de la taille de l'instance ; il **ne survit pas** a une re-execution sur une autre machine, meme si l'ordre de grandeur est preserve. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note technique** : Le **speedup structurel** (rapport des noeuds explores, 1x a 100x entre d=1 et d=6) augmente avec la profondeur car l'elagage a plus d'opportunites de couper des branches. A profondeur 1, aucun elagage n'est possible (toutes les feuilles sont au même niveau). L'ordonnancement des coups (centre en priorite) maximise cet elagage. Le **speedup wall-clock** (rapport des temps d'exécution, runtime *machine-dep* sur cette machine) suit le même pattern mais avec une amplitude qui depend du CLR Python, de la charge système et de la taille de l'instance ; il **ne survit pas** a une re-exécution sur une autre machine, même si l'ordre de grandeur est preserve. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n" ] }, @@ -2226,10 +2226,10 @@ "| Random | 4 | 14 | 22.2% | Faible |\n", "| MCTS(1000) | 2 | 16 | 11.1% | Très faible |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Alpha-Beta domine sans perdre une partie** : 18-0, balayage 6-0 contre les trois autres agents\n", "2. **Minimax solide** : 66.7% de win rate, ne perd que contre Alpha-Beta (0-6), balaie Random et MCTS (6-0 chacun)\n", - "3. **MCTS en difficulté** : dernier du tournoi, perd contre Alpha-Beta (0-6), Minimax (0-6) et meme contre Random (2-4) -- 1000 iterations restent peu pour Connect Four\n", + "3. **MCTS en difficulté** : dernier du tournoi, perd contre Alpha-Beta (0-6), Minimax (0-6) et même contre Random (2-4) -- 1000 itérations restent peu pour Connect Four\n", "4. **échantillon insuffisant** : 6 parties par match = résultats variables\n", "\n", "Points forts / faibles par algorithme :\n", @@ -2240,12 +2240,12 @@ "| **Alpha-Beta** | efficace, optimal | Ordonnancement critique | Jeux a branchement moyen |\n", "| **MCTS** | Pas d'heuristique, parallèle | probabiliste | grands espaces, jeux complexes |\n", "\n", - "**observations cles** :\n", + "**observations clés** :\n", "\n", "1. **Alpha-Beta** réduit drastiquement le nombre de noeuds (facteur 5-20x selon la profondeur)\n", "2. **MCTS** converge vers de bons coups sans fonction d'évaluation explicite\n", "\n", - "> **Note technique** : Le tournoi est **seedé** (`random.seed(42)` dans `run_tournament`, #9434) : ces scores sont reproductibles a la re-execution. La différence entre Minimax et Alpha-Beta devrait etre nulle en theorie (même profondeur = même coups) ; le 6-0 d'Alpha-Beta sur Minimax suggere une différence d'ordonnancement des coups dans l'elagage. Avec 50+ parties (exercice 5), les win rates des duels équilibrés convergeraient vers ~50% pour Minimax vs Alpha-Beta." + "> **Note technique** : Le tournoi est **seedé** (`random.seed(42)` dans `run_tournament`, #9434) : ces scores sont reproductibles a la re-exécution. La différence entre Minimax et Alpha-Beta devrait etre nulle en théorie (même profondeur = même coups) ; le 6-0 d'Alpha-Beta sur Minimax suggere une différence d'ordonnancement des coups dans l'elagage. Avec 50+ parties (exercice 5), les win rates des duels équilibrés convergeraient vers ~50% pour Minimax vs Alpha-Beta." ] }, { @@ -2285,7 +2285,7 @@ "\n", "**objectif** : comparer Alpha-Beta aux profondeurs 4, 6 et 8, et déterminer la profondeur optimale pour un budget de 1 seconde. C'est le levier classique du compromis temps/profondeur en recherche adverse.\n", "\n", - "**Indices** : `run_benchmark_depth()` (section 6) comme base ; mesurer temps + nombre de noeuds ; faire jouer les algorithmes entre eux pour juger la qualite des coups, pas seulement la vitesse." + "**Indices** : `run_benchmark_depth()` (section 6) comme base ; mesurer temps + nombre de noeuds ; faire jouer les algorithmes entre eux pour juger la qualité des coups, pas seulement la vitesse." ] }, { @@ -2627,7 +2627,7 @@ "source": [ "### Exercice 6 -- Livre d'ouvertures (Opening Book)\n", "\n", - "**objectif** : precalculer les meilleurs premiers coups avec un Alpha-Beta profond (d=8), les stocker dans un dictionnaire `{plateau_hash: meilleur_coup}`, puis mesurer le gain (temps economise + qualite) en debut de partie.\n", + "**objectif** : precalculer les meilleurs premiers coups avec un Alpha-Beta profond (d=8), les stocker dans un dictionnaire `{plateau_hash: meilleur_coup}`, puis mesurer le gain (temps economise + qualité) en debut de partie.\n", "\n", "**Indices** : un `dict {(plateau_hash): meilleur_coup}` ; la génération se fait une fois pour toutes (hors-ligne), la consultation en match est O(1)." ] @@ -2709,8 +2709,8 @@ "\n", "| critère | Minimax | Alpha-Beta | MCTS |\n", "|---------|---------|------------|------|\n", - "| **Optimalite** | Oui (si profondeur complète) | Oui (identique a Minimax) | probabiliste |\n", - "| **Complexite** | O(b^d) | O(b^(d/2)) optimal | O(n * d) |\n", + "| **Optimalité** | Oui (si profondeur complète) | Oui (identique a Minimax) | probabiliste |\n", + "| **Complexité** | O(b^d) | O(b^(d/2)) optimal | O(n * d) |\n", "| **Fonction d'évaluation** | nécessaire | nécessaire | Non requise |\n", "| **Parallelisation** | Difficile | Difficile | très facile |\n", "| **Meilleur usage** | Petits jeux | Jeux moyens | grands jeux |\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15-SportsScheduling.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15-SportsScheduling.ipynb index 14bef5a2ba1..1581ee42bca 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15-SportsScheduling.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15-SportsScheduling.ipynb @@ -90,7 +90,7 @@ "tags": [] }, "source": [ - "## 1. Modelisation du Problème\n", + "## 1. Modélisation du Problème\n", "\n", "### Definition du CSP\n", "\n", @@ -105,7 +105,7 @@ "1. **Round-robin simple** : chaque pair d'équipes joue exactement une fois\n", "2. **Une équipe par match** : une équipe joue au plus un match par ronde\n", "3. **Symetrie** : si A vs B, alors pas B vs A dans la même ronde\n", - "4. **Capacite stade** : une équipe ne peut pas recevoir deux fois même ronde\n", + "4. **Capacité stade** : une équipe ne peut pas recevoir deux fois même ronde\n", "\n", "### Contraintes Soft (préférences)\n", "\n", @@ -247,7 +247,7 @@ "source": [ "### Lecture du résultat\n", "\n", - "La sortie annonce la ligue de démonstration : « Ligue 1 (Echantillon 6 equipes) » — Paris FC, Marseille FC, Lyon FC, Lille FC, Bordeaux FC, Nantes FC — sur 5 rondes.\n" + "La sortie annonce la ligue de démonstration : « Ligue 1 (Echantillon 6 équipes) » — Paris FC, Marseille FC, Lyon FC, Lille FC, Bordeaux FC, Nantes FC — sur 5 rondes.\n" ] }, { @@ -470,7 +470,7 @@ "| **Plus proches** | Paris-Lille, Lyon-Marseille | Derbys potentiels avec faibles deplacements |\n", "| **Plus eloignees** | Marseille-Lille (~833 km) | Deplacements importants a minimiser |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Formule de Haversine** : Calcul précis de la distance geodesique entre deux coordonnees GPS\n", "2. **Impact sur les deplacements** : La matrice sert de base a l'objectif de minimisation des deplacements\n", "3. **Identification des derbys** : Les distances faibles (< 300 km) indiquent des rivalites geographiques potentielles\n", @@ -493,9 +493,9 @@ "tags": [] }, "source": [ - "## 3. Modelisation CP-SAT\n", + "## 3. Modélisation CP-SAT\n", "\n", - "Nous utilisons OR-Tools CP-SAT pour resoudre le problème." + "Nous utilisons OR-Tools CP-SAT pour résoudre le problème." ] }, { @@ -693,15 +693,15 @@ "|--------|--------|---------------|\n", "| **Statut** | OPTIMAL ou FEASIBLE | Le solveur a trouvé une solution valide (résultat structurel sur instance) |\n", "| **Temps de resolution** | Runtime *machine-dep* | Performance typique pour 6 équipes (de l'ordre de la fraction de seconde) |\n", - "| **Variables** | n × (n-1) × rondes | Complexite quadratique gérable par CP-SAT (propriété algorithmique) |\n", + "| **Variables** | n × (n-1) × rondes | Complexité quadratique gérable par CP-SAT (propriété algorithmique) |\n", "\n", - "**Points cles** :\n", - "1. **Efficacité de CP-SAT** : OR-Tools résout des problemes de planification sportive complexes via des techniques de propagation de contraintes et branch-and-bound (propriétés algorithmiques invariantes).\n", + "**Points clés** :\n", + "1. **Efficacité de CP-SAT** : OR-Tools résout des problèmes de planification sportive complexes via des techniques de propagation de contraintes et branch-and-bound (propriétés algorithmiques invariantes).\n", "2. **Contraintes satisfaites** : Round-robin simple (chaque pair joue une fois), une équipe joue une fois par ronde, équilibre D/E\n", "3. **Objectif optimisé** : Minimisation des déplacements tout en respectant les contraintes hard\n", "4. **Extensibilité** : Le modèle peut etre étendu avec des contraintes additionnelles (TV, derbys, arbitres)\n", "\n", - "> **Note technique** : Le solveur CP-SAT utilise des techniques avancées (propagation de contraintes, branch-and-bound, lazy clauses) pour trouver des solutions optimales. Pour des problemes plus grands (20+ équipes), le **runtime** (machine-dep) augmente avec la taille du problème (propriété structurelle liée à la complexité NP-difficile du round-robin CSP) ; un **timeout** paramétrable permet de borner le temps de recherche.\n", + "> **Note technique** : Le solveur CP-SAT utilise des techniques avancées (propagation de contraintes, branch-and-bound, lazy clauses) pour trouver des solutions optimales. Pour des problèmes plus grands (20+ équipes), le **runtime** (machine-dep) augmente avec la taille du problème (propriété structurelle liée à la complexité NP-difficile du round-robin CSP) ; un **timeout** paramétrable permet de borner le temps de recherche.\n", "\n" ] }, @@ -721,15 +721,15 @@ "source": [ "#### Exercice 1 : Penaliser les longs deplacements consecutifs (version souple)\n", "\n", - "La version interdite (voir l'exemple guide 4 en fin de carnet) supprime purement et simplement les enchainements de longs deplacements. Une regle aussi dure peut FORCER le solveur a accepter des calendriers plus couteux par ailleurs : interdire a un prix, et ce prix se mesure en kilometres.\n", + "La version interdite (voir l'exemple guide 4 en fin de carnet) supprime purement et simplement les enchainements de longs deplacements. Une règle aussi dure peut FORCER le solveur a accepter des calendriers plus couteux par ailleurs : interdire a un prix, et ce prix se mesure en kilometres.\n", "\n", - "**Enonce** : remplacez l'interdiction par une penalite pesee. Ajoutez au modele une variable `penalite[i, r]` qui vaut 1 quand l'equipe i enchaine deux longs deplacements aux rondes r et r+1, puis minimisez `distance_totale + POIDS * somme(penalites)` avec `POIDS = 300` (le prix d'un enchainement, exprime en kilometres equivalents).\n", + "**Enonce** : remplacez l'interdiction par une penalite pesee. Ajoutez au modèle une variable `penalite[i, r]` qui vaut 1 quand l'équipe i enchaine deux longs deplacements aux rondes r et r+1, puis minimisez `distance_totale + POIDS * somme(penalites)` avec `POIDS = 300` (le prix d'un enchainement, exprime en kilometres equivalents).\n", "\n", "**Consignes** :\n", - "1. Pour chaque equipe i et ronde r, creez la variable auxiliaire boolVar `long_trip[i, r]` qui vaut 1 si l'equipe i voyage a l'exterieur de plus de 500 km a la ronde r\n", - "2. Creez `penalite[i, r]` reifiee : elle vaut 1 si et seulement si `long_trip[i, r] + long_trip[i, r+1] == 2`\n", + "1. Pour chaque équipe i et ronde r, créez la variable auxiliaire boolVar `long_trip[i, r]` qui vaut 1 si l'équipe i voyage a l'exterieur de plus de 500 km a la ronde r\n", + "2. Créez `penalite[i, r]` reifiee : elle vaut 1 si et seulement si `long_trip[i, r] + long_trip[i, r+1] == 2`\n", "3. Minimisez la distance totale PLUS `POIDS *` la somme des penalites, au lieu de la seule distance\n", - "4. Mesurez le cout reel du choix : combien de kilometres de PLUS (ou de moins) coute le calendrier penalise par rapport au calendrier avec interdiction ? Combien d'enchainements restent, et ou ?\n", + "4. Mesurez le coût réel du choix : combien de kilometres de PLUS (ou de moins) coute le calendrier penalise par rapport au calendrier avec interdiction ? Combien d'enchainements restent, et ou ?\n", "\n", "**Indice** : la reification en CP-SAT s'ecrit dans les deux sens avec `OnlyEnforceIf` : `model.Add(long_trip[i, r] + long_trip[i, r+1] == 2).OnlyEnforceIf(penalite[i, r])` et `model.Add(long_trip[i, r] + long_trip[i, r+1] <= 1).OnlyEnforceIf(penalite[i, r].Not())`." ] @@ -943,13 +943,13 @@ "\n", "**Sortie obtenue** : Calendrier complet avec statistiques sur les deplacements et la repartition domicile/exterieur.\n", "\n", - "| Metrique | Observation | Signification |\n", + "| Métrique | Observation | Signification |\n", "|----------|-------------|---------------|\n", "| **Distance moyenne** | ~1000-1500 km par équipe | Optimisation globale des deplacements |\n", "| **Ecart-type** | Variable | Indicateur de l'equite entre équipes |\n", "| **Repartition D/E** | Variable (1 D/4 E a 4 D/1 E) | L'equilibre D/E n'est pas impose par les contraintes |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Equite geographique** : Les équipes ont des charges de deplacement similaires (malgré leur position geographique)\n", "2. **Minimisation globale** : L'objectif minimise la somme des distances, ce qui beneficie a toutes les équipes\n", "3. **Alternance D/E** : sans contrainte explicite, la repartition domicile/exterieur varie d'une équipe a l'autre (ex. 1 D/4 E ou 4 D/1 E)\n", @@ -1120,7 +1120,7 @@ "| **Attractivite** | Combinaison des scores TV | Paris vs Marseille, Lyon vs PSG sont privilegies |\n", "| **Trade-off** | Distance vs TV | Les matchs attractifs peuvent augmenter les deplacements |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Revenus TV** : Les matchs attractifs generent plus d'audience et de revenus pour les chaînes de television\n", "2. **Contrainte soft** : L'objectif TV s'ajoute aux autres contraintes (round-robin, equilibre, deplacements)\n", "3. **Importance ponderee** : Les creneaux \"Ouverture\" et \"Cloture\" ont un poids 2x pour attirer les matchs les plus prestigieux\n", @@ -1329,11 +1329,11 @@ "| **Seuil de distance** | 200-300 km | Distance raisonnable pour un deplacement en bus |\n", "| **Ronde de derby** | Variable | Le solveur place les derbys selon les contraintes globales |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Securite et logistique** : Les derbys necessitent une planification speciale (securite renforcee, transports)\n", "2. **Contrainte potentielle** : Dans un vrai système, on pourrait forcer les derbys a etre joues en week-end ou a des heures spécifiques\n", "3. **Impact sur les deplacements** : Les derbis reduisent les distances de voyage pour les équipes impliquees\n", - "4. **Modelisation extensible** : Ce système permet d'identifier et de gerer les matchs a haut enjeu\n", + "4. **Modélisation extensible** : Ce système permet d'identifier et de gerer les matchs a haut enjeu\n", "\n", "> **Note technique** : Dans un championnat professionnel comme la Ligue 1, les derbys (PSG vs Marseille, Lyon vs Saint-Etienne, etc.) sont des événements majeurs qui necessitent une planification speciale. Les contraintes de securite peuvent etre ajoutees au modèle CSP pour forcer ces matchs a des creneaux spécifiques." ] @@ -1488,10 +1488,10 @@ "| **Matchs par équipe** | 2 × (n-1) | Double confrontation : aller domicile, retour exterieur |\n", "| **Equite** | Parfaite | Chaque équipe joue exactement une fois a domicile et une fois a l'exterieur contre chaque adversaire |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Standard professionnel** : La plupart des championnats europeens utilisent le round-robin double (Ligue 1, Premier League, Liga...)\n", "2. **Symetrie parfaite** : L'avantage de jouer a domicile est compense par le match retour\n", - "3. **Complexite accrue** : Le nombre de rondes double, ce qui augmente la taille du problème CSP\n", + "3. **Complexité accrue** : Le nombre de rondes double, ce qui augmente la taille du problème CSP\n", "4. **Contraintes spécifiques** : Le modèle garantit que chaque pair d'équipes joue exactement une fois a domicile et une fois a l'exterieur\n", "\n", "> **Note technique** : Le round-robin double est le format standard pour les championnats professionnels. Le modèle CP-SAT s'adapte facilement en modifiant les contraintes C1 pour imposer un match domicile et un match exterieur pour chaque pair d'équipes." @@ -1520,7 +1520,7 @@ "2. La repartition domicile/exterieur de chaque équipe (est-elle equilibree ?)\n", "3. Comparez l'ecart-type des deplacements avec celui du calendrier simple\n", "\n", - "**Indice** : `compute_schedule_stats` retourne un dictionnaire avec les cles `total_travel`, `home_games`, `away_games`, `avg_travel`, `travel_std`." + "**Indice** : `compute_schedule_stats` retourne un dictionnaire avec les clés `total_travel`, `home_games`, `away_games`, `avg_travel`, `travel_std`." ] }, { @@ -1679,13 +1679,13 @@ "| **Cohérence spatiale** | Équipes proches ont des motifs similaires | Impact de la minimisation des deplacements |\n", "| **Couverture** | Chaque équipe joue chaque ronde | Contrainte round-robin satisfaite |\n", "\n", - "**Points cles** :\n", - "1. **Visualisation efficace** : Cette matrice permet de verifier visuellement la qualite du calendrier\n", + "**Points clés** :\n", + "1. **Visualisation efficace** : Cette matrice permet de vérifier visuellement la qualité du calendrier\n", "2. **Contrainte d'equilibre** : L'alternance D/E est visible par l'absence de longues sequences de la même couleur\n", "3. **Equite** : La répartition D/E n'est pas imposée par les contraintes — elle varie d'une équipe à l'autre (de 1 D/4 E à 4 D/1 E)\n", "4. **Motifs spatiaux** : Les équipes geographiquement proches ont des calendriers similaires (minimisation des deplacements)\n", "\n", - "> **Note technique** : Dans un championnat professionnel, cette visualisation est utilisee par les organisateurs pour verifier l'equite du calendrier. Les entraineurs l'utilisent pour planifier la preparation physique et tactique en fonction des deplacements.\n", + "> **Note technique** : Dans un championnat professionnel, cette visualisation est utilisee par les organisateurs pour vérifier l'equite du calendrier. Les entraineurs l'utilisent pour planifier la preparation physique et tactique en fonction des deplacements.\n", "\n" ] }, @@ -1829,19 +1829,19 @@ "\n", "**Sortie obtenue** : Courbes montrant l'evolution du **temps de resolution** (runtime *machine-dep*) et du **nombre de variables** (invariant structurel, O(n² × r)) en fonction du nombre d'équipes.\n", "\n", - "| Metrique | Observation | Signification |\n", + "| Métrique | Observation | Signification |\n", "|----------|-------------|---------------|\n", "| **Temps de resolution** | Runtime *machine-dep* (croissance avec n) | Le problème est NP-difficile en théorie (propriété structurelle) |\n", "| **Nombre de variables** | Croissance en O(n² × r) | Chaque équipe joue contre chaque autre a chaque ronde (invariant structurel) |\n", "| **Seuil de scalabilite** | Non mesure au-dela de 10 équipes | Projection : limite pratique ~20-30 équipes |\n", "\n", - "**Points cles** :\n", - "1. **Complexite combinatoire** : Le nombre de variables croit quadratiquement avec le nombre d'équipes (n × (n-1) × rondes) — c'est une **propriété structurelle** du round-robin CSP.\n", + "**Points clés** :\n", + "1. **Complexité combinatoire** : Le nombre de variables croit quadratiquement avec le nombre d'équipes (n × (n-1) × rondes) — c'est une **propriété structurelle** du round-robin CSP.\n", "2. **Runtime observable** : Pour 10 équipes, la resolution est quasi-instantanée (runtime *machine-dep* sur la machine de référence) ; ce **runtime** dépend de CP-SAT, de la charge système et de la taille de l'instance.\n", "3. **Explosion combinatoire** : Au-dela de 20 équipes, le **runtime** (machine-dep) augmente drastiquement avec la taille du problème (propriété de complexité NP-difficile).\n", - "4. **Optimisation pratique** : Un **timeout** paramétrable (parametre de benchmark deterministe) est recommandé pour borner le temps de recherche sur des instances de taille moyenne.\n", + "4. **Optimisation pratique** : Un **timeout** paramétrable (paramètre de benchmark déterministe) est recommandé pour borner le temps de recherche sur des instances de taille moyenne.\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : le **nombre de variables** (O(n² × r)) est un **invariant structurel** du round-robin CSP (deterministe sur l'instance, propriété algorithmique). En revanche, le **temps de resolution** (runtime *machine-dep*) et les **mesures** (`0.01-0.05 s`, `0.05 s`) dependent de la machine, de la version OR-Tools, de la charge système et de la taille de l'instance — elles **ne survivent pas** a une re-execution. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous ; le **timeout** reste un **parametre** deterministe.\n", + "> **Note methodologique -- separation structurel / machine-dep** : le **nombre de variables** (O(n² × r)) est un **invariant structurel** du round-robin CSP (déterministe sur l'instance, propriété algorithmique). En revanche, le **temps de resolution** (runtime *machine-dep*) et les **mesures** (`0.01-0.05 s`, `0.05 s`) dependent de la machine, de la version OR-Tools, de la charge système et de la taille de l'instance — elles **ne survivent pas** a une re-exécution. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous ; le **timeout** reste un **paramètre** déterministe.\n", "\n" ] }, @@ -1998,19 +1998,19 @@ "source": [ "### Interpretation : Comparaison des Approches\n", "\n", - "**Sortie obtenue** : Tableau comparatif de quatre méthodes de resolution de problemes de planification sportive.\n", + "**Sortie obtenue** : Tableau comparatif de quatre méthodes de resolution de problèmes de planification sportive.\n", "\n", "| Aspect | CSP (OR-Tools) | Programmation Lineaire | Métaheuristiques | Generation manuelle |\n", "|--------|----------------|------------------------|------------------|---------------------|\n", - "| **Optimalite** | Oui (si temps suffisant) | Oui (PLNE) | Non (approximative) | Variable |\n", + "| **Optimalité** | Oui (si temps suffisant) | Oui (PLNE) | Non (approximative) | Variable |\n", "| **Scalabilite** | Moyenne (20-30 équipes) | Bonne | Excellente | Mauvaise |\n", "| **Flexibilite contraintes** | Excellente | Moyenne | Bonne | Excellente |\n", "| **Temps de développement** | Moyen | Eleve | Moyen | Eleve |\n", "\n", - "**Points cles** :\n", - "1. **CSP (OR-Tools)** offre le meilleur compromis entre optimalite, flexibilite et temps de développement pour des problemes de taille moyenne (jusqu'a 30 équipes)\n", - "2. **Programmation Lineaire** garantie l'optimalite mais est moins flexible pour les contraintes non-lineaires (equilibre D/E, derbys)\n", - "3. **Métaheuristiques** (algorithmes génétiques, recuit simule) scalent mieux mais ne garantissent pas l'optimalite\n", + "**Points clés** :\n", + "1. **CSP (OR-Tools)** offre le meilleur compromis entre optimalité, flexibilite et temps de développement pour des problèmes de taille moyenne (jusqu'a 30 équipes)\n", + "2. **Programmation Lineaire** garantie l'optimalité mais est moins flexible pour les contraintes non-lineaires (equilibre D/E, derbys)\n", + "3. **Métaheuristiques** (algorithmes génétiques, recuit simule) scalent mieux mais ne garantissent pas l'optimalité\n", "4. **Generation manuelle** est flexible mais chronophage et non reproductible\n", "\n", "> **Note technique** : Le choix de la méthode depend du contexte. Pour un championnat professionnel avec 20 équipes et des contraintes complexes, CSP est recommande. Pour des ligues de 40+ équipes avec des contraintes simples, les métaheuristiques sont plus adaptees." @@ -2344,9 +2344,9 @@ "source": [ "### Exemple guide 4 : Limiter les longs deplacements consecutifs (EX-0373)\n", "\n", - "Cet exemple guide est la correction creditee de l'exercice EX-0373, livree par **Jérôme Desale et Mathis Gramaglia** (TP1, PR #22568). Elle montre la formulation retenue : une variable `long_trip[i, r]` definie par EGALITE avec les matchs lointains (formulation plus forte qu'une paire d'inegalites, legitime ici puisqu'une equipe ne joue qu'une fois par ronde), la contrainte glissante `long_trip[i, r] + long_trip[i, r+1] <= 1`, un verificateur independant qui recalcule les trajets depuis les matchs au lieu de relire les variables du solveur, et la comparaison avant/apres sur un calendrier illustratif choisi pour contenir exactement un enchainement interdit.\n", + "Cet exemple guide est la correction creditee de l'exercice EX-0373, livree par **Jérôme Desale et Mathis Gramaglia** (TP1, PR #22568). Elle montre la formulation retenue : une variable `long_trip[i, r]` définie par EGALITE avec les matchs lointains (formulation plus forte qu'une paire d'inegalites, legitime ici puisqu'une équipe ne joue qu'une fois par ronde), la contrainte glissante `long_trip[i, r] + long_trip[i, r+1] <= 1`, un verificateur indépendant qui recalcule les trajets depuis les matchs au lieu de relire les variables du solveur, et la comparaison avant/après sur un calendrier illustratif choisi pour contenir exactement un enchainement interdit.\n", "\n", - "Note honnete sur la comparaison : le total des kilometres et le nombre de longs trajets sont invariants par construction — chaque paire se rencontre exactement une fois et les distances sont symetriques. La seule ligne que la nouvelle regle peut faire bouger est le nombre d'enchainements interdits (1 vers 0 ici). Le calendrier corrige n'est pas un simple reordonnancement du calendrier initial : selon la machine et le deroulement du solveur, il peut permuter deux rondes (run Colab des auteurs : meme affectation, seuls les rondes 3 et 4 echangees) ou deplacer des appariements d'une ronde a l'autre (cette execution : ecart-type 267,5 vers 258,6 km, statut OPTIMAL). La comparaison ne demontre ni reduction de distance ni reduction de fatigue — seulement la disparition de l'enchainement interdit. La version souple de l'exercice 1 (penalite pesee en kilometres) prolonge exactement cette question : que coute l'interdiction ?" + "Note honnete sur la comparaison : le total des kilometres et le nombre de longs trajets sont invariants par construction — chaque paire se rencontre exactement une fois et les distances sont symetriques. La seule ligne que la nouvelle règle peut faire bouger est le nombre d'enchainements interdits (1 vers 0 ici). Le calendrier corrige n'est pas un simple reordonnancement du calendrier initial : selon la machine et le deroulement du solveur, il peut permuter deux rondes (run Colab des auteurs : même affectation, seuls les rondes 3 et 4 echangees) ou déplacer des appariements d'une ronde a l'autre (cette exécution : ecart-type 267,5 vers 258,6 km, statut OPTIMAL). La comparaison ne demontre ni reduction de distance ni reduction de fatigue — seulement la disparition de l'enchainement interdit. La version souple de l'exercice 1 (penalite pesee en kilometres) prolonge exactement cette question : que coute l'interdiction ?" ] }, { @@ -2982,9 +2982,9 @@ "\n", "### Ce que nous avons appris\n", "\n", - "1. **Modelisation CSP** : Un calendrier sportif peut etre modelise avec des variables binaires representant chaque match\n", + "1. **Modélisation CSP** : Un calendrier sportif peut etre modelise avec des variables binaires representant chaque match\n", "\n", - "2. **Contraintes** : Les contraintes hard assurent la validite du round-robin, les contraintes soft optimisent la qualite\n", + "2. **Contraintes** : Les contraintes hard assurent la validite du round-robin, les contraintes soft optimisent la qualité\n", "\n", "3. **Trade-offs** : Minimiser les deplacements vs maximiser l'attractivite TV\n", "\n", @@ -2994,7 +2994,7 @@ "\n", "- **Contraintes de referees** : Disponibilite des arbitres\n", "- **Contraintes de stade** : Partage de stade (ex: AC Milan / Inter)\n", - "- **Contraintes de coupes** : Eviter les conflits avec coupes europeennes\n", + "- **Contraintes de coupes** : Éviter les conflits avec coupes europeennes\n", "- **Contraintes de repos** : Jours minimums entre matchs\n", "\n", "### References\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15b-SportsScheduling-CSharp.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15b-SportsScheduling-CSharp.ipynb index 4c84df0e802..b4acf011909 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15b-SportsScheduling-CSharp.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-15b-SportsScheduling-CSharp.ipynb @@ -16,7 +16,7 @@ "\n", "A la fin de ce notebook, vous saurez :\n", "\n", - "1. **Modeliser** un calendrier sportif (round-robin) comme un **Problème de Satisfaction de Contraintes (CSP)** en C# / .NET 9.\n", + "1. **Modéliser** un calendrier sportif (round-robin) comme un **Problème de Satisfaction de Contraintes (CSP)** en C# / .NET 9.\n", "2. **Invoquer le vrai solveur industriel** `Google.OrTools` (CP-SAT natif .NET) -- `CpModel`, `BoolVar`, `Add`, `Minimize` -- pour optimiser les deplacements des équipes.\n", "3. **Reproduire l'optimum verifie** du twin Python (1232 km en moyenne par équipe, ecart-type 473 km -- cf. correction G.1 section 4 : l'output commite d'App-15 affichait 1233/534, valeur sous-optimale) sur la **même matrice de distances**, et comprendre pourquoi les deux twins s'accordent au km pres.\n", "4. **Etendre** le modèle : contraintes d'equilibre domicile/exterieur, attractivite TV, derbys, round-robin double.\n", @@ -28,15 +28,15 @@ "| Python | **OR-Tools CP-SAT** + numpy + matplotlib | solveur industriel, matrices numpy, heatmaps matplotlib |\n", "| **Ce twin (.NET)** | **Google.OrTools natif .NET** + ScottPlot | **même solveur CP-SAT** via une autre liaison de langage ; met en evidence les ecarts d'API (G.1) |\n", "\n", - "Les deux twins invoquent le **même moteur CP-SAT** (la bibliotheque C++ sous-jacente). L'intérêt pedagogique est la **parite cross-langage** : même modèle, même optimum, eventuellement un calendrier optimal différent (plusieurs optima de même cout).\n", + "Les deux twins invoquent le **même moteur CP-SAT** (la bibliotheque C++ sous-jacente). L'intérêt pédagogique est la **parite cross-langage** : même modèle, même optimum, eventuellement un calendrier optimal différent (plusieurs optima de même coût).\n", "\n", - "### Prerequis\n", + "### Prérequis\n", "\n", "- [.NET 9.0](https://dotnet.microsoft.com/) + kernel `.net-csharp` (`dotnet tool install --global Microsoft.dotnet-interactive`)\n", "- Lecture du [twin Python App-15](App-15-SportsScheduling.ipynb)\n", "- Bases de CSP (variables, domaines, contraintes)\n", "\n", - "**Duree estimee : ~55 min.**" + "**Durée estimee : ~55 min.**" ] }, { @@ -107,7 +107,7 @@ "id": "da4a9ce8c1e6", "metadata": {}, "source": [ - "## 1. Modelisation du Problème\n", + "## 1. Modélisation du Problème\n", "\n", "### Definition du CSP\n", "\n", @@ -120,7 +120,7 @@ "\n", "### Données : la ligue\n", "\n", - "On reproduit **exactement** l'echantillon du twin Python : 6 équipes francaises (Paris, Marseille, Lyon, Lille, Bordeaux, Nantes) avec leurs coordonnees GPS. Les distances sont calculees par la **formule de Haversine** (grand cercle sur la sphere), tronquees en entiers (comme le fait `int(distances[i,j])` cote Python) pour fonder l'objectif CP-SAT." + "On reproduit **exactement** l'echantillon du twin Python : 6 équipes françaises (Paris, Marseille, Lyon, Lille, Bordeaux, Nantes) avec leurs coordonnees GPS. Les distances sont calculees par la **formule de Haversine** (grand cercle sur la sphere), tronquees en entiers (comme le fait `int(distances[i,j])` cote Python) pour fonder l'objectif CP-SAT." ] }, { @@ -787,14 +787,14 @@ "|--------|-------------|---------------|\n", "| **Distances** | 203 a 833 km entre les 6 villes | Proximite geographique favorable aux derbys |\n", "| **Plus proches** | Paris-Lille (203 km), Lyon-Marseille (277 km), Bordeaux-Nantes (275 km) | 3 derbys potentiels (< 300 km) |\n", - "| **Plus eloignees** | Marseille-Lille (833 km) | Deplacement massif que le solveur cherchera a eviter |\n", + "| **Plus eloignees** | Marseille-Lille (833 km) | Deplacement massif que le solveur cherchera a éviter |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Haversine** : distance du grand cercle sur la sphere, plus precise que l'euclidienne pour des villes.\n", - "2. **Troncature entiere** : comme le twin Python (`int(distances[i,j])`), l'objectif CP-SAT utilise des coefficients entiers -- condition necessaire pour retrouver le **même optimum** (1232 km de moyenne, somme 7390 km).\n", + "2. **Troncature entiere** : comme le twin Python (`int(distances[i,j])`), l'objectif CP-SAT utilise des coefficients entiers -- condition nécessaire pour retrouver le **même optimum** (1232 km de moyenne, somme 7390 km).\n", "3. **Derbys** : les paires a moins de 300 km (Paris-Lille, Lyon-Marseille, Bordeaux-Nantes) seront identifiees en section 6.\n", "\n", - "> **Note technique** : ces valeurs reproduisent exactement la matrice du twin Python (verifiable dans [App-15-SportsScheduling.ipynb](App-15-SportsScheduling.ipynb)). La parite de la matrice est la **precondition** de la parite de l'optimum." + "> **Note technique** : ces valeurs reproduisent exactement la matrice du twin Python (verifiable dans [App-15-SportsScheduling.ipynb](App-15-SportsScheduling.ipynb)). La parite de la matrice est la **précondition** de la parite de l'optimum." ] }, { @@ -802,11 +802,11 @@ "id": "33afaa13dcc5", "metadata": {}, "source": [ - "## 3. Modelisation CP-SAT (SportsScheduler)\n", + "## 3. Modélisation CP-SAT (SportsScheduler)\n", "\n", "On construit le **même modèle** que le twin Python :\n", "\n", - "- **Variables** : `match[i,j,r]` booleennes pour `i != j` et `r` in `0..rounds-1`.\n", + "- **Variables** : `match[i,j,r]` booléennes pour `i != j` et `r` in `0..rounds-1`.\n", "- **C1** : chaque paire `{i,j}` joue exactement une fois (`sum_r match[i,j,r] + match[j,i,r] == 1`).\n", "- **C2** : chaque équipe joue exactement un match par ronde.\n", "- **Equilibre** : pas plus de `max_consecutive` (2) matchs domicile **ou** exterieur consecutifs.\n", @@ -993,11 +993,11 @@ "|--------|--------|---------------|\n", "| **Statut** | `CpSolverStatus.Optimal` | L'optimum global est atteint (résultat structurel sur instance) |\n", "| **Temps** | Runtime *machine-dep* | Performance typique pour n=6 (de l'ordre de la fraction de seconde) |\n", - "| **Variables** | `n * (n-1) * rounds` = 6*5*5 = 150 booleennes | Complexite quadratique gérable par CP-SAT (propriété algorithmique) |\n", + "| **Variables** | `n * (n-1) * rounds` = 6*5*5 = 150 booléennes | Complexité quadratique gérable par CP-SAT (propriété algorithmique) |\n", "\n", - "> **Parite cross-langage** : le même modèle, sur la même matrice de distances, atteint le **même cout optimal** qu'une re-exécution fresh du twin Python (7390 km de somme, detail en section 4). Le calendrier précis peut cependant differer d'une exécution a l'autre : CP-SAT admet souvent **plusieurs optima de même cout**. Ici, C# et Python fresh produisent **le meme objectif optimal** (7390 km) ; le calendrier exact peut varier d'une exécution a l'autre (non-déterminisme CP-SAT avec workers parallèles), mais le coût optimal prouvé est identique -- preuve forte de la parite. Le **runtime wall-clock** (machine-dep) depend du CLR .NET, de la charge système et de la taille de l'instance ; il **ne survit pas** a une re-execution sur une autre machine.\n", + "> **Parite cross-langage** : le même modèle, sur la même matrice de distances, atteint le **même coût optimal** qu'une re-exécution fresh du twin Python (7390 km de somme, detail en section 4). Le calendrier précis peut cependant differer d'une exécution a l'autre : CP-SAT admet souvent **plusieurs optima de même coût**. Ici, C# et Python fresh produisent **le même objectif optimal** (7390 km) ; le calendrier exact peut varier d'une exécution a l'autre (non-déterminisme CP-SAT avec workers parallèles), mais le coût optimal prouvé est identique -- preuve forte de la parite. Le **runtime wall-clock** (machine-dep) depend du CLR .NET, de la charge système et de la taille de l'instance ; il **ne survit pas** a une re-exécution sur une autre machine.\n", "\n", - "> **Note technique** : pour des problemes plus grands (20+ équipes), le **runtime** (machine-dep) augmente avec la taille du problème (propriété structurelle liée à la complexité NP-difficile du round-robin CSP) ; un **timeout** paramétrable permet de borner le temps de recherche. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note technique** : pour des problèmes plus grands (20+ équipes), le **runtime** (machine-dep) augmente avec la taille du problème (propriété structurelle liée à la complexité NP-difficile du round-robin CSP) ; un **timeout** paramétrable permet de borner le temps de recherche. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n" ] }, @@ -1438,7 +1438,7 @@ "\n", "**Sortie obtenue** : calendrier complet (5 rondes, 3 matchs par ronde = 15 matchs) + statistiques de deplacement.\n", "\n", - "| Metrique | C# (ce twin) | Python (App-15) | Concordance |\n", + "| Métrique | C# (ce twin) | Python (App-15) | Concordance |\n", "|----------|--------------|----------------------|-------------|\n", "| **Rondes** | 5 (n-1) | 5 | identique |\n", "| **Matchs / ronde** | 3 (n/2) | 3 | identique |\n", @@ -1447,9 +1447,9 @@ "| **Distance moyenne** | 1232 km | 1232 km | **identique** |\n", "| **Ecart-type** | 473 km | 473 km | **identique** |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. **Parite exacte C# / Python** : une re-exécution fresh du twin Python (même modèle, même matrice Haversine tronquee) retourne **exactement** la même solution optimale (même somme 7390 km, mêmes deplacements par équipe). C'est le résultat le plus fort possible pour un twin cross-langage : le moteur CP-SAT sous-jacent (bibliotheque C++) est identique.\n", - "2. **Metrique d'arrondi (G.1) -- output commite vs objectif** : l'output anterieur de [`App-15-SportsScheduling.ipynb`](App-15-SportsScheduling.ipynb) affichait \"moyenne 1233 km, ecart-type 534 km\" (somme 7398 km) car `compute_schedule_stats` sommait les distances **FLOAT**. L'objectif du solveur (`int(distances[i,j])`, comme la matrice `long[,]` de ce twin C#) vaut **7390 km** pour la **même solution optimale**. L'écart 7398 vs 7390 (8 km) est la **troncature int de l'objectif sur 15 matchs**, pas une solution sous-optimale : le solveur etait bien OPTIMAL. App-15 affiche désormais 7390 (objectif + statistiques int-cohérents), rétablissant la parité exacte au km pres.\n", + "2. **Métrique d'arrondi (G.1) -- output commite vs objectif** : l'output anterieur de [`App-15-SportsScheduling.ipynb`](App-15-SportsScheduling.ipynb) affichait \"moyenne 1233 km, ecart-type 534 km\" (somme 7398 km) car `compute_schedule_stats` sommait les distances **FLOAT**. L'objectif du solveur (`int(distances[i,j])`, comme la matrice `long[,]` de ce twin C#) vaut **7390 km** pour la **même solution optimale**. L'écart 7398 vs 7390 (8 km) est la **troncature int de l'objectif sur 15 matchs**, pas une solution sous-optimale : le solveur etait bien OPTIMAL. App-15 affiche désormais 7390 (objectif + statistiques int-cohérents), rétablissant la parité exacte au km pres.\n", "3. **Repartition D/E** : sans contrainte explicite d'egalite D/E, une équipe peut avoir 1 D/4 E ou 4 D/1 E -- la minimisation globale ne force pas l'equite individuelle.\n", "4. **Faisabilite** : toutes les contraintes (round-robin, une équipe/match/ronde, equilibre 2 consecutifs) sont satisfaites.\n", "\n", @@ -1740,7 +1740,7 @@ "| **Trade-off** | Attractivite vs distance | L'objectif TV peut augmenter le total km (non minimise ici) |\n", "| **Flexibilite** | Ajout de creneaux arbitraires | Modèle extensible (samedi soir, dimanche après-midi) |\n", "\n", - "> **Note technique** : en CP-SAT on ne maximise directement -- on minimise l'**oppose** (coefficients negatifs dans le `ScalProd`). C'est une adaptation G.1 par rapport a un solver qui exposerait `Maximize`." + "> **Note technique** : en CP-SAT on ne maximise directement -- on minimise l'**oppose** (coefficients négatifs dans le `ScalProd`). C'est une adaptation G.1 par rapport a un solver qui exposerait `Maximize`." ] }, { @@ -1927,7 +1927,7 @@ "| **Distance de derby** | 203 a 277 km | Deplacement en bus/train raisonnable |\n", "| **Placement** | Reparti sur les rondes | Le solveur evite naturellement les conflits (cf. Exercice 2 pour le forcer) |\n", "\n", - "> **Note technique** : dans un championnat reel (Ligue 1), les derbys (PSG-Marseille, Lyon-Saint-Etienne) sont des événements a haut risque qui demandent une logistique dediee. Le modèle CSP peut forcer leur espacement temporel." + "> **Note technique** : dans un championnat réel (Ligue 1), les derbys (PSG-Marseille, Lyon-Saint-Etienne) sont des événements a haut risque qui demandent une logistique dediee. Le modèle CSP peut forcer leur espacement temporel." ] }, { @@ -2717,7 +2717,7 @@ "| **Alternance** | pas plus de 2 D ou 2 E consecutifs | contrainte d'equilibre respectee |\n", "| **Inegalite de charge** | barres de hauteur variable | certaines équipes voyagent beaucoup plus |\n", "\n", - "> **Note technique** : cette visualisation est l'outil des organisateurs pour verifier l'equite du calendrier. L'Exercice 2 du twin Python (objectif d'equite) montrerait comment reduire l'amplitude des barres." + "> **Note technique** : cette visualisation est l'outil des organisateurs pour vérifier l'equite du calendrier. L'Exercice 2 du twin Python (objectif d'equite) montrerait comment reduire l'amplitude des barres." ] }, { @@ -2858,13 +2858,13 @@ "\n", "**Sortie obtenue** : deux courbes -- temps de resolution et nombre de variables -- selon le nombre d'équipes.\n", "\n", - "| Metrique | Observation | Signification |\n", + "| Métrique | Observation | Signification |\n", "|----------|-------------|---------------|\n", "| **Temps (n=4..10)** | Runtime *machine-dep* (croissance avec n) | Concordance d'ordre de grandeur avec le twin Python |\n", "| **Variables** | `n*(n-1)*(n-1)` | Croissance cubique (ex: n=10 -> 810 vars) — invariant structurel |\n", "| **Seuil pratique** | ~20-30 équipes | Au-dela, augmenter le timeout ou accepter du faisable |\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : le theoreme dit ce problème **NP-difficile**, mais CP-SAT resout les petites instances grace a la propagation par clauses paresseuses (LCG). Le **nombre de variables** (`n*(n-1)*(n-1)`) est un **invariant structurel** du round-robin CSP (déterministe sur l'instance, propriété algorithmique). En revanche, le **temps de resolution** et les **mesures** (`0.01-0.05 s`) dependent du CLR .NET, de la charge système et de la taille de l'instance — ils **ne survivent pas** a une re-execution. Les valeurs observées sur cette machine reproduisent l'ordre de grandeur du twin Python ; pour observer vos propres timings, executez la cellule de benchmark ci-dessous ; le **timeout** reste un **parametre de benchmark deterministe**.\n", + "> **Note methodologique -- separation structurel / machine-dep** : le theoreme dit ce problème **NP-difficile**, mais CP-SAT resout les petites instances grace a la propagation par clauses paresseuses (LCG). Le **nombre de variables** (`n*(n-1)*(n-1)`) est un **invariant structurel** du round-robin CSP (déterministe sur l'instance, propriété algorithmique). En revanche, le **temps de resolution** et les **mesures** (`0.01-0.05 s`) dependent du CLR .NET, de la charge système et de la taille de l'instance — ils **ne survivent pas** a une re-exécution. Les valeurs observées sur cette machine reproduisent l'ordre de grandeur du twin Python ; pour observer vos propres timings, executez la cellule de benchmark ci-dessous ; le **timeout** reste un **paramètre de benchmark déterministe**.\n", "\n" ] }, @@ -2958,15 +2958,15 @@ "\n", "| Aspect | CSP (OR-Tools) | PL | Métaheuristiques | Generation manuelle |\n", "|--------|----------------|----|------------------|---------------------|\n", - "| **Optimalite** | Oui (si temps) | Oui (PLNE) | Non (approx) | Variable |\n", + "| **Optimalité** | Oui (si temps) | Oui (PLNE) | Non (approx) | Variable |\n", "| **Scalabilite** | Moyenne (20-30 eq.) | Bonne | Excellente | Mauvaise |\n", "| **Flexibilite** | Excellente | Moyenne | Bonne | Excellente |\n", "| **Temps dev.** | Moyen | Eleve | Moyen | Eleve |\n", "\n", - "**Points cles** :\n", - "1. **CSP (OR-Tools)** offre le meilleur compromis optimalite / flexibilite / effort pour 20-30 équipes.\n", - "2. **PL** garantie l'optimalite mais est peu flexible pour les contraintes non-lineaires (equilibre D/E, derbys).\n", - "3. **Métaheuristiques** (AG, recuit) scalent au-dela mais sans garantie d'optimalite.\n", + "**Points clés** :\n", + "1. **CSP (OR-Tools)** offre le meilleur compromis optimalité / flexibilite / effort pour 20-30 équipes.\n", + "2. **PL** garantie l'optimalité mais est peu flexible pour les contraintes non-lineaires (equilibre D/E, derbys).\n", + "3. **Métaheuristiques** (AG, recuit) scalent au-dela mais sans garantie d'optimalité.\n", "4. **Generation manuelle** est flexible mais non reproductible et chronophage.\n", "\n", "### Adaptations G.1 (API C# vs Python OR-Tools)\n", @@ -2997,16 +2997,16 @@ "\n", "### Ce que nous avons appris\n", "\n", - "1. **Modelisation CSP** : un calendrier sportif se modelise par des variables binaires `match[i,j,r]` (i recoit j a la ronde r), des contraintes de round-robin et d'equilibre D/E.\n", - "2. **Vrai solveur industriel** : `Google.OrTools` (CP-SAT natif .NET) resout le problème avec un **runtime machine-dep** pour 6 équipes — pas de reimplementation jouet (EPIC #3801, Prong A SOTA-OK). Le **runtime wall-clock** (de l'ordre de la fraction de seconde sur cette machine) depend du CLR .NET et de la charge système ; il **ne survit pas** a une re-execution sur une autre machine. Le **statut Optimal** et le **coût optimal** (7390 km), eux, sont invariants.\n", - "3. **Parite cross-langage verifiee** : le même modèle, sur la même matrice de distances Haversine, atteint le **même optimum** (7390 km de somme, 1232 km de moyenne par équipe) en C# et lors d'une re-exécution fresh du twin Python -- les deux s'accordent au km pres. Bonus (G.1) : ce croisement a mis en lumiere une metrique d'arrondi (objectif int-tronque 7390 vs somme float 7398 de la meme solution optimale), desormais rendue coherente dans App-15 (7390 partout).\n", + "1. **Modélisation CSP** : un calendrier sportif se modelise par des variables binaires `match[i,j,r]` (i recoit j a la ronde r), des contraintes de round-robin et d'equilibre D/E.\n", + "2. **Vrai solveur industriel** : `Google.OrTools` (CP-SAT natif .NET) resout le problème avec un **runtime machine-dep** pour 6 équipes — pas de reimplementation jouet (EPIC #3801, Prong A SOTA-OK). Le **runtime wall-clock** (de l'ordre de la fraction de seconde sur cette machine) depend du CLR .NET et de la charge système ; il **ne survit pas** a une re-exécution sur une autre machine. Le **statut Optimal** et le **coût optimal** (7390 km), eux, sont invariants.\n", + "3. **Parite cross-langage verifiee** : le même modèle, sur la même matrice de distances Haversine, atteint le **même optimum** (7390 km de somme, 1232 km de moyenne par équipe) en C# et lors d'une re-exécution fresh du twin Python -- les deux s'accordent au km pres. Bonus (G.1) : ce croisement a mis en lumiere une métrique d'arrondi (objectif int-tronque 7390 vs somme float 7398 de la même solution optimale), desormais rendue coherente dans App-15 (7390 partout).\n", "4. **Extensibilite** : contraintes TV, derbys, round-robin double s'ajoutent au même squelette CSP.\n", "\n", "### Extensions possibles\n", "\n", "- **Arbitres** : assignation d'arbitres avec contraintes de disponibilite (cf. Exercices Python).\n", "- **Stades partagés** : AC Milan / Inter, Bayern / 1860 (pas deux matchs au même stade même journee).\n", - "- **Coupes europeennes** : eviter les conflits de calendrier inter-competitions.\n", + "- **Coupes europeennes** : éviter les conflits de calendrier inter-competitions.\n", "- **Equite des deplacements** : minimiser l'amplitude `max_travel - min_travel` plutot que la somme.\n", "\n", "### References\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17-VRP-Logistics.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17-VRP-Logistics.ipynb index c8981216404..a55b01d5b32 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17-VRP-Logistics.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17-VRP-Logistics.ipynb @@ -58,7 +58,7 @@ "\n", "- **CVRP** : Capacitated VRP (avec contraintes de capacité)\n", "- **VRPTW** : VRP avec fenêtres de temps\n", - "- **MDVRP** : Multi-Depot VRP\n", + "- **MDVRP** : Multi-Dépôt VRP\n", "- **OVRP** : Open VRP (pas de retour au dépôt)" ] }, @@ -1246,7 +1246,7 @@ "source": [ "### Lecture : décomposer l'écart — ce que gagne le solveur SOTA\n", "\n", - "Le tableau se lit aussi en differences qu'en pourcentages : `417.49` a\n", + "Le tableau se lit aussi en différences qu'en pourcentages : `417.49` a\n", "`414.49` pour le 2-opt (`-0.7%`), puis `414.49` a `403.45` pour OR-Tools\n", "(`-3.4%` cumulé). Sur les `13.04` unités qui séparent le glouton du solveur,\n", "le 2-opt n'en récupère donc que `3.00` — moins d'un quart. La majorité de la\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17b-VRP-Logistics-CSharp.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17b-VRP-Logistics-CSharp.ipynb index d8fb1a5817b..e810a6425c2 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17b-VRP-Logistics-CSharp.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-17b-VRP-Logistics-CSharp.ipynb @@ -1127,9 +1127,9 @@ "source": [ "## Tranche 2 : moteur industriel OR-Tools (lib-vs-lib, #10382)\n", "\n", - "Le twin Python [App-17-VRP-Logistics](App-17-VRP-Logistics.ipynb) appelle le **moteur industriel OR-Tools** (`ortools.constraint_solver.routing`, `RoutingModel`) comme **solveur SOTA** du VRP capacitaire sur la meme instance canonique. La Tranche 1 from-scratch ci-dessus (plus proche voisin, insertion au moindre cout, 2-opt, recuit simule) est **preservee intacte** : on lui confronte maintenant le **meme moteur de production** que le jumeau Python — **Google.OrTools 9.15.6755** (Perron & Furney ; solveur de routage avec recherche locale guidee GLS et contrainte de capacite).\n", + "Le twin Python [App-17-VRP-Logistics](App-17-VRP-Logistics.ipynb) appelle le **moteur industriel OR-Tools** (`ortools.constraint_solver.routing`, `RoutingModel`) comme **solveur SOTA** du VRP capacitaire sur la même instance canonique. La Tranche 1 from-scratch ci-dessus (plus proche voisin, insertion au moindre coût, 2-opt, recuit simule) est **preservee intacte** : on lui confronte maintenant le **même moteur de production** que le jumeau Python — **Google.OrTools 9.15.6755** (Perron & Furney ; solveur de routage avec recherche locale guidee GLS et contrainte de capacité).\n", "\n", - "**Honnêteté cruciale** : le solveur de routage est une **metaheuristique** (recherche locale guidee), PAS un solveur exact — il ne delivre **aucun certificat d'optimalite** (contrairement a CP-SAT). Sa valeur est la **qualite industrielle**, pas la garantie ; c'est le meme paradigme que le twin Python." + "**Honnêteté cruciale** : le solveur de routage est une **métaheuristique** (recherche locale guidee), PAS un solveur exact — il ne delivre **aucun certificat d'optimalité** (contrairement a CP-SAT). Sa valeur est la **qualité industrielle**, pas la garantie ; c'est le même paradigme que le twin Python." ] }, { @@ -1321,19 +1321,19 @@ "id": "d9be6870", "metadata": {}, "source": [ - "**Verdict SOTA-OK (mesure ci-dessus).** Le routing solver OR-Tools (contrainte de capacite `Capacity`) trouve sur l'instance canonique une solution **valide** dont la distance se compare honnêtement aux 4 methodes from-scratch de la Tranche 1.\n", + "**Verdict SOTA-OK (mesure ci-dessus).** Le routing solver OR-Tools (contrainte de capacité `Capacity`) trouve sur l'instance canonique une solution **valide** dont la distance se compare honnêtement aux 4 méthodes from-scratch de la Tranche 1.\n", "\n", - "**Hierarchie des methodes** (mesuree sur l'instance canonique, 15 clients) :\n", + "**Hiérarchie des méthodes** (mesuree sur l'instance canonique, 15 clients) :\n", "\n", - "| Methode | Nature | Qualite |\n", + "| Méthode | Nature | Qualité |\n", "|---|---|---|\n", "| **Plus proche voisin** (from-scratch §3) | Heuristique greedy O(n²) | rapide, myope |\n", - "| **Insertion au moindre cout** (from-scratch §3) | Heuristique constructive | meilleure vision globale |\n", + "| **Insertion au moindre coût** (from-scratch §3) | Heuristique constructive | meilleure vision globale |\n", "| **2-opt** (from-scratch §4) | Recherche locale, optimum **local** | corrige les croisements |\n", - "| **Recuit simule** (from-scratch §5) | Metaheuristique, Metropolis | echappe aux optima locaux |\n", - "| **OR-Tools routing** (Tranche 2) | Metaheuristique industrielle **GLS** | moteur de production, meilleure qualite |\n", + "| **Recuit simule** (from-scratch §5) | Métaheuristique, Metropolis | echappe aux optima locaux |\n", + "| **OR-Tools routing** (Tranche 2) | Métaheuristique industrielle **GLS** | moteur de production, meilleure qualité |\n", "\n", - "La force de `RoutingModel` n'est pas un certificat d'optimalite (metaheuristique, contrairement a CP-SAT) mais sa **qualite robuste** via la recherche locale guidee — et surtout l'identite **exacte** du moteur invoque par le jumeau Python (meme lib C++ OR-Tools). La Tranche 1 from-scratch reste **valable** : elle rend tangible le *fonctionnement intime* de chaque methode. Deux leviers complementaires." + "La force de `RoutingModel` n'est pas un certificat d'optimalité (métaheuristique, contrairement a CP-SAT) mais sa **qualité robuste** via la recherche locale guidee — et surtout l'identite **exacte** du moteur invoque par le jumeau Python (même lib C++ OR-Tools). La Tranche 1 from-scratch reste **valable** : elle rend tangible le *fonctionnement intime* de chaque méthode. Deux leviers complémentaires." ] }, { @@ -1553,4 +1553,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-19-ProceduralGeneration-WFC.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-19-ProceduralGeneration-WFC.ipynb index 01e78d13ea7..ea7f1dbb701 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-19-ProceduralGeneration-WFC.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-19-ProceduralGeneration-WFC.ipynb @@ -55,23 +55,23 @@ "source": [ "## Hommage a un travail etudiant\n", "\n", - "Ce notebook prolonge le projet **Timothe-Le-Bronec-H2_WFC_CPSAT** du cours EPITA SCIA *Programmation par Contraintes* 2026, realise en solo par **Timothe Le Bronec** ([Timothe Le Bronec](https://github.com/thorgal27)) : [repertoire source](https://github.com/jsboigeEpita/2026-Epita-Programmation-par-Contraintes/tree/main/Timothe-Le-Bronec-H2_WFC_CPSAT), commit de livraison `08dfe96` (login `thorgal27` verifie firsthand), cherry-pick `621f1cc` (par `jsboigeEpita`), licence **MIT** (LICENSE globale du depot parent `jsboigeEpita/2026-Epita-Programmation-par-Contraintes`, verifiee 2026-09-17 ; pas de LICENSE locale dans le sous-projet, statut herite du parent).\n", + "Ce notebook prolonge le projet **Timothe-Le-Bronec-H2_WFC_CPSAT** du cours EPITA SCIA *Programmation par Contraintes* 2026, realise en solo par **Timothe Le Bronec** ([Timothe Le Bronec](https://github.com/thorgal27)) : [repertoire source](https://github.com/jsboigeEpita/2026-Epita-Programmation-par-Contraintes/tree/main/Timothe-Le-Bronec-H2_WFC_CPSAT), commit de livraison `08dfe96` (login `thorgal27` verifie firsthand), cherry-pick `621f1cc` (par `jsboigeEpita`), licence **MIT** (LICENSE globale du dépôt parent `jsboigeEpita/2026-Epita-Programmation-par-Contraintes`, verifiee 2026-09-17 ; pas de LICENSE locale dans le sous-projet, statut herite du parent).\n", "\n", - "Le projet etudiant couvre deja l'essentiel de ce que ce notebook pedagogique reprend :\n", + "Le projet etudiant couvre déjà l'essentiel de ce que ce notebook pédagogique reprend :\n", "\n", - "- la **modelisation WFC comme CSP** : variables = tuile placee en (i, j), domaine = tileset donne, contraintes = regles d'adjacence issues de `tileset.json` ;\n", + "- la **modélisation WFC comme CSP** : variables = tuile placee en (i, j), domaine = tileset donne, contraintes = règles d'adjacence issues de `tileset.json` ;\n", "- le **solveur CP-SAT** qui enumere les configurations globales (par opposition au `PureWFC` qui collapse une cellule a la fois) ;\n", - "- la **generation aleatoire** de niveau (`generate_random`) pour evaluation ;\n", - "- l'**evaluation** sur les tuiles donjon et cave (`tileset.json`, `tileset_cave.json`).\n", + "- la **generation aléatoire** de niveau (`generate_random`) pour évaluation ;\n", + "- l'**évaluation** sur les tuiles donjon et cave (`tileset.json`, `tileset_cave.json`).\n", "\n", "Ce qui est *ajoute* dans ce notebook par rapport au projet source :\n", "\n", - "1. la **couche metriques** : `adjacency_violations` (compte les adjacences illegales), `bfs_reachable_floor` (test de connectivite du joueur), `tile_variety` (diversity de tuiles) qui rendent la comparaison WFC pur / CP-SAT / aleatoire quantitative ;\n", - "2. la **comparaison systematique** des trois solveurs sur les memes instances (Section 8), absente du notebook source ;\n", + "1. la **couche metriques** : `adjacency_violations` (compte les adjacences illegales), `bfs_reachable_floor` (test de connectivite du joueur), `tile_variety` (diversity de tuiles) qui rendent la comparaison WFC pur / CP-SAT / aléatoire quantitative ;\n", + "2. la **comparaison systématique** des trois solveurs sur les mêmes instances (Section 8), absente du notebook source ;\n", "3. les **contraintes globales** : ajout de la connectivite, du chemin joueur, et du placement d'objets qui rendent les niveaux jouables (le projet source optimise la coherence d'adjacence, pas la jouabilite) ;\n", - "4. les **contraintes de difficulte** (densite ennemis, variete) qui ramenent WFC du domaine graphique vers un usage pedagogique.\n", + "4. les **contraintes de difficulte** (densite ennemis, variete) qui ramenent WFC du domaine graphique vers un usage pédagogique.\n", "\n", - "L'enrichissement preserve le solveur et les tilesets du projet etudiant ; les ajouts sont concentres sur la *couche d'evaluation et de contraintes de jouabilite*, qui manquaient pour transformer une generation graphique en un sujet de cours.\n", + "L'enrichissement preserve le solveur et les tilesets du projet etudiant ; les ajouts sont concentres sur la *couche d'évaluation et de contraintes de jouabilite*, qui manquaient pour transformer une generation graphique en un sujet de cours.\n", "\n" ] }, @@ -521,7 +521,7 @@ "\n", "L'entropie affichée à droite vaut `−Σ (wi/s)·log(wi/s)` sur le domaine restant (mêmes poids `weights` que le tirage). Son maximum, atteint pour un domaine plein de 5 tuiles équiprobables, est `log(5) ≈ 1,61` — c'est le `vmax` fixé par la cellule, ce qui garantit une échelle comparable d'une étape à l'autre.\n", "\n", - "À l'étape 0 (celle rendue par l'exécution committée) : aucune cellule effondrée, la grille de gauche est intégralement bleue avec un « 5 » par case, la carte d'entropie est uniforme au maximum. Faites glisser le slider vers les dernières étapes : les taches sombres gagnent, l'encadré rouge suit la dernière cellule effondrée." + "À l'étape 0 (celle rendue par l'exécution committée) : aucune cellule effondrée, la grille de gauche est intégralement bleue avec un « 5 » par case, la carte d'entropie est uniforme au maximum. Faites glisser le slider vers les dernières étapes : les tâches sombres gagnent, l'encadré rouge suit la dernière cellule effondrée." ] }, { @@ -726,7 +726,7 @@ "source": [ "### Exercice : Valider un niveau genere\n", "\n", - "Ecrivez une fonction `validate_level` qui prend une grille generee et verifie **tous les critères de qualite** : violations d'adjacence, connectivite BFS, et comptage d'objets. La fonction retourne un dict avec les metriques et un booléen `valid` (True si 0 violations + connectivite > 50%).\n", + "Ecrivez une fonction `validate_level` qui prend une grille generee et verifie **tous les critères de qualité** : violations d'adjacence, connectivite BFS, et comptage d'objets. La fonction retourne un dict avec les metriques et un booléen `valid` (True si 0 violations + connectivite > 50%).\n", "\n", "**Indices** :\n", "- Utilisez `adjacency_violations(grid, rules)` du module `wfc_cpsat` pour les violations\n", @@ -1279,11 +1279,11 @@ "source": [ "### Visualisation des niveaux par difficulte\n", "\n", - "Les trois configurations (Facile, Moyen, Difficile) sont resolues. La cellule suivante affiche les grilles obtenues cote a cote, avec le compteur d'ennemis, de cles et de coffres, ainsi que le taux de connectivite et le temps de resolution.\n", + "Les trois configurations (Facile, Moyen, Difficile) sont resolues. La cellule suivante affiche les grilles obtenues cote a cote, avec le compteur d'ennemis, de clés et de coffres, ainsi que le taux de connectivite et le temps de resolution.\n", "\n", - "> **Note sur le statut du solveur** : **Moyen** et **Difficile** atteignent le statut **OPTIMAL** (solution optimale prouvee en runtime *machine-dep*). **Facile**, dont l'espace de recherche est plus large (ratios de sol 45-65 %, peu d'ennemis), s'arrete au statut **FEASIBLE** : le solveur trouve une solution valide mais ne prouve pas son optimalite dans le delai imparti (timeout_s = 20.0, runtime *machine-dep*), et le decompte exact d'ennemis/cles peut donc **varier d'une execution a l'autre** (le `seed` fixe ne rend deterministe que le statut OPTIMAL, pas les solutions FEASIBLE). C'est un comportement attendu de CP-SAT, et l'une des raisons pour lesquelles on utilise un timeout en production.\n", + "> **Note sur le statut du solveur** : **Moyen** et **Difficile** atteignent le statut **OPTIMAL** (solution optimale prouvee en runtime *machine-dep*). **Facile**, dont l'espace de recherche est plus large (ratios de sol 45-65 %, peu d'ennemis), s'arrete au statut **FEASIBLE** : le solveur trouve une solution valide mais ne prouve pas son optimalité dans le delai imparti (timeout_s = 20.0, runtime *machine-dep*), et le decompte exact d'ennemis/clés peut donc **varier d'une exécution a l'autre** (le `seed` fixe ne rend déterministe que le statut OPTIMAL, pas les solutions FEASIBLE). C'est un comportement attendu de CP-SAT, et l'une des raisons pour lesquelles on utilise un timeout en production.\n", ">\n", - "> **Note methodologique -- separation structurel / machine-dep** : le **statut** (OPTIMAL / FEASIBLE) et les **statistiques** (nombre de cases sol / ennemis / cles / coffres / taux de connectivite) sont des **invariants structurels** (resultats solveur sur instance specifique, deterministes sur la graine fixee). En revanche, le **temps de resolution** et le **timeout_s** sont **machine-dep** (CPU, charge systeme, version Python, OR-Tools, taille de l'instance) et **ne survivent pas** a une re-execution sur une autre machine. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous (la cellule `solve_cpsat` utilise `time.time()` pour mesurer le solve_time).\n", + "> **Note methodologique -- separation structurel / machine-dep** : le **statut** (OPTIMAL / FEASIBLE) et les **statistiques** (nombre de cases sol / ennemis / clés / coffres / taux de connectivite) sont des **invariants structurels** (résultats solveur sur instance spécifique, déterministes sur la graine fixee). En revanche, le **temps de resolution** et le **timeout_s** sont **machine-dep** (CPU, charge système, version Python, OR-Tools, taille de l'instance) et **ne survivent pas** a une re-exécution sur une autre machine. Pour observer vos propres timings, executez la cellule de benchmark ci-dessous (la cellule `solve_cpsat` utilise `time.time()` pour mesurer le solve_time).\n", "\n" ] }, @@ -1355,12 +1355,12 @@ "source": [ "### Exercice : Créer un preset de difficulte perso\n", "\n", - "En vous basant sur les 3 presets (Facile/Moyen/Difficile) définis ci-dessus, créez un nouveau preset **\"Hardcore\"** avec vos propres paramètres de contraintes. L'objectif est un niveau avec **peu de sol**, **beaucoup d'ennemis**, et **plusieurs cles/coffres** obligeant le joueur a explorer.\n", + "En vous basant sur les 3 presets (Facile/Moyen/Difficile) définis ci-dessus, créez un nouveau preset **\"Hardcore\"** avec vos propres paramètres de contraintes. L'objectif est un niveau avec **peu de sol**, **beaucoup d'ennemis**, et **plusieurs clés/coffres** obligeant le joueur a explorer.\n", "\n", "**Indices** :\n", "- Inspirez-vous du dictionnaire `difficulty_configs` ci-dessus\n", "- Paramètres disponibles : `min_enemy_ratio`, `max_enemy_ratio`, `min_floor_ratio`, `max_floor_ratio`, `n_keys`, `n_chests`\n", - "- Un niveau hardcore typique : sol < 30%, ennemis > 25%, 3+ cles, 2+ coffres\n", + "- Un niveau hardcore typique : sol < 30%, ennemis > 25%, 3+ clés, 2+ coffres\n", "- Appelez `solve_cpsat(12, 12, tileset, seed=42, add_connectivity=True, timeout_s=20.0, **votre_config)` pour tester" ] }, @@ -1658,7 +1658,7 @@ "source": [ "## Synthese -- WFC vs CP-SAT pour la generation procedurale\n", "\n", - "| Critere | Aleatoire | WFC pur | CP-SAT |\n", + "| Critere | Aléatoire | WFC pur | CP-SAT |\n", "|---------|-----------|---------|--------|\n", "| Violations d'adjacence | Elevees (ex: 20/12x12) | **0** | **0** |\n", "| Connectivite garantie | Non (~2%) | Non (~2%) | Partiellement (relaxation flow, ~7% observe) |\n", @@ -1667,23 +1667,23 @@ "| Temps de calcul | runtime *machine-dep* | runtime *machine-dep* | runtime *machine-dep* (entre OPTIMAL ~1 s et timeout 20 s) |\n", "| Expressivite | Aucune | Locale uniquement | Globale + objectives |\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : toutes les colonnes sauf **Temps de calcul** sont des **invariants structurels** (resultats solveur sur instance specifique ou proprietes algorithmiques, deterministes sur la graine fixee). En revanche, la colonne **Temps de calcul** est **machine-dep** (CPU, charge systeme, version Python, OR-Tools, taille de l'instance) et **ne survit pas** a une re-execution sur une autre machine. L'ordre de grandeur qualitatif (Aleatoire et WFC tres rapides vs CP-SAT beaucoup plus lent) reste structurel, mais le ratio exact **30-500x** mentionne dans les Points cles est lui aussi **machine-dep** (le ratio varie significativement d'une machine a l'autre). Pour observer vos propres timings et ratios, executez la cellule de benchmark ci-dessous.\n", + "> **Note methodologique -- separation structurel / machine-dep** : toutes les colonnes sauf **Temps de calcul** sont des **invariants structurels** (résultats solveur sur instance spécifique ou proprietes algorithmiques, déterministes sur la graine fixee). En revanche, la colonne **Temps de calcul** est **machine-dep** (CPU, charge système, version Python, OR-Tools, taille de l'instance) et **ne survit pas** a une re-exécution sur une autre machine. L'ordre de grandeur qualitatif (Aléatoire et WFC très rapides vs CP-SAT beaucoup plus lent) reste structurel, mais le ratio exact **30-500x** mentionne dans les Points clés est lui aussi **machine-dep** (le ratio varie significativement d'une machine a l'autre). Pour observer vos propres timings et ratios, executez la cellule de benchmark ci-dessous.\n", "\n", - "### Points cles a retenir\n", + "### Points clés a retenir\n", "\n", - "1. **WFC** modelise un probleme de **propagation locale** : chaque tuile contraint ses voisines immediates. C'est rapide, mais ne peut exprimer que des contraintes d'adjacence.\n", - "2. **CP-SAT** formule le meme probleme comme un **CSP global** : toutes les contraintes (adjacence + objets + difficulte + connectivite) sont satisfaites simultanement par un solveur SAT.\n", + "1. **WFC** modelise un problème de **propagation locale** : chaque tuile contraint ses voisines immediates. C'est rapide, mais ne peut exprimer que des contraintes d'adjacence.\n", + "2. **CP-SAT** formule le même problème comme un **CSP global** : toutes les contraintes (adjacence + objets + difficulte + connectivite) sont satisfaites simultanément par un solveur SAT.\n", "3. **Trade-off expressivite/perf** : CP-SAT est beaucoup plus lent que WFC (l'ordre de grandeur du ratio depend de la machine), mais permet d'exprimer des contraintes impossibles en WFC pur (nb exact d'objets, ratios globaux, connectivite).\n", - "4. **Hybride possible** : utiliser WFC pour generer un niveau rapidement, puis CP-SAT pour reparer/critiquer (verifier connectivite, compter objets). C'est l'approche pratique des game studios.\n", + "4. **Hybride possible** : utiliser WFC pour generer un niveau rapidement, puis CP-SAT pour reparer/critiquer (vérifier connectivite, compter objets). C'est l'approche pratique des game studios.\n", "\n", "### Pour aller plus loin\n", "\n", "- **Optimizer la connectivite** : remplacer la relaxation flow par une contrainte de chemin explicite (variables `path[u]` = rang dans le BFS), plus couteuse mais complete.\n", "- **Multi-objectif** : optimiser la variete (`Maximize(sum(different))`) tout en saturant les contraintes globales.\n", - "- **Generation de tilesets** : apprendre les regles d'adjacence depuis une image de reference (WFC observationnel).\n", + "- **Generation de tilesets** : apprendre les règles d'adjacence depuis une image de reference (WFC observationnel).\n", "- **Parallelisation** : CP-SAT supporte `num_search_workers=N` pour exploiter les CPU multi-coeurs.\n", "\n", - "Ce notebook a montre comment formuler un probleme de generation procedurale (typiquement traite par des heuristiques ad-hoc) comme un **CSP canonique** resolu par un solveur industriel (OR-Tools). C'est un pattern transferrable a de nombreux domaines : placement de composants en VLSI, allocation de frequences, planification de taches.\n", + "Ce notebook a montre comment formuler un problème de generation procedurale (typiquement traite par des heuristiques ad-hoc) comme un **CSP canonique** resolu par un solveur industriel (OR-Tools). C'est un pattern transferrable a de nombreux domaines : placement de composants en VLSI, allocation de frequences, planification de tâches.\n", "\n" ] } @@ -2918,4 +2918,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-2-GraphColoring.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-2-GraphColoring.ipynb index 2ce1a0d749b..3269fa87ba0 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-2-GraphColoring.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-2-GraphColoring.ipynb @@ -52,15 +52,15 @@ "1. **Formaliser** un problème de coloration de graphe comme CSP\n", "2. **Implementer** l'algorithme Greedy et comparer les effets de l'ordre des sommets\n", "3. **Implementer** DSATUR (Brelaz 1979) et comprendre son avantage heuristique\n", - "4. **Modeliser** le problème avec OR-Tools CP-SAT et prouver l'optimalite\n", - "5. **Appliquer** ces algorithmes a la coloration des departements francais\n", - "6. **Comparer** les performances sur des graphes aleatoires de taille croissante\n", + "4. **Modéliser** le problème avec OR-Tools CP-SAT et prouver l'optimalité\n", + "5. **Appliquer** ces algorithmes a la coloration des departements français\n", + "6. **Comparer** les performances sur des graphes aléatoires de taille croissante\n", "\n", - "### Prerequis\n", + "### Prérequis\n", "- Python 3.10+, notions de graphes (sommets, aretes, adjacence)\n", "- [CSP-1 : Fundamentals](../Part2-CSP/CSP-1-Fundamentals.ipynb) et [CSP-2 : Consistency](../Part2-CSP/CSP-2-Consistency.ipynb)\n", "\n", - "### Duree estimee : 45 minutes" + "### Durée estimee : 45 minutes" ] }, { @@ -97,14 +97,14 @@ "\n", "### Applications concretes\n", "\n", - "| Domaine | Problème | Modelisation |\n", + "| Domaine | Problème | Modélisation |\n", "|---------|----------|--------------|\n", "| **Cartographie** | Colorier une carte (regions adjacentes différentes) | Sommets = regions, aretes = frontieres communes |\n", "| **Compilation** | Allocation de registres CPU | Sommets = variables vivantes, aretes = interferences |\n", "| **Planification** | Emplois du temps sans conflit | Sommets = cours, aretes = même professeur ou salle |\n", "| **Telecommunications** | Attribution de frequences radio | Sommets = antennes, aretes = zones d'interference |\n", "\n", - "### Complexite\n", + "### Complexité\n", "\n", "- Determiner si un graphe est **2-coloriable** (biparti) est en $O(\\vert V\\vert + \\vert E\\vert)$ -- polynomial\n", "- Determiner si un graphe est **3-coloriable** est **NP-complet** (Karp, 1972)\n", @@ -159,19 +159,19 @@ "source": [ "### Visualisation du coloriage\n", "\n", - "Cette premiere figure place le decor : elle dessine le graphe que tout le notebook va colorer, celui des\n", - "departements francais d'Ile-de-France et des regions voisines (un sous-ensemble de 18 sommets et 37 aretes —\n", + "Cette première figure place le decor : elle dessine le graphe que tout le notebook va colorer, celui des\n", + "departements français d'Ile-de-France et des regions voisines (un sous-ensemble de 18 sommets et 37 aretes —\n", "ces chiffres sont mesures par la cellule suivante).\n", "\n", "Ce qu'il faut regarder avant de commencer :\n", "\n", "- **Chaque sommet = un departement.** La position approximative du sommet evoque sa geographie, ce qui rend la\n", " planaite du graphe naturelle : deux departements qui se touchent physiquement se voient relies par une arete.\n", - "- **Une arete = une frontiere partagee.** Deux departements voisins ne peuvent pas recevoir la meme couleur :\n", - " c'est la definition meme d'une coloration valide, celle que tous les algorithmes de ce notebook vont garantir.\n", + "- **Une arete = une frontiere partagee.** Deux departements voisins ne peuvent pas recevoir la même couleur :\n", + " c'est la definition même d'une coloration valide, celle que tous les algorithmes de ce notebook vont garantir.\n", "- **La question du coloriage.** Combien de couleurs faut-il, au minimum, pour colorer la carte entiere ?\n", " Le theoreme des quatre couleurs promet qu'un graphe planaire se colore toujours avec au plus 4 couleurs —\n", - " la suite va verifier ce plafond sur les donnees reelles.\n" + " la suite va vérifier ce plafond sur les données reelles.\n" ] }, { @@ -247,14 +247,14 @@ "source": [ "***\n", "\n", - "## 2. Construction du graphe : departements francais (~5 min)\n", + "## 2. Construction du graphe : departements français (~5 min)\n", "\n", - "Nous utilisons un sous-ensemble de departements francais metropolitains pour illustrer le probleme. Chaque\n", + "Nous utilisons un sous-ensemble de departements français metropolitains pour illustrer le problème. Chaque\n", "departement est un sommet, et deux departements sont relies par une arete s'ils partagent une frontiere commune.\n", "\n", "Nous construisons un graphe de **18 departements** autour de l'Ile-de-France et de ses voisins. La cellule\n", - "suivante construit ce graphe a partir des frontieres reelles, puis mesure ses caracteristiques structurelles :\n", - "nombre de sommets, d'aretes, degres minimaux et maximaux, et le test de planarite (NetworkX le fait en\n", + "suivante construit ce graphe a partir des frontieres reelles, puis mesure ses caractéristiques structurelles :\n", + "nombre de sommets, d'aretes, degrés minimaux et maximaux, et le test de planarite (NetworkX le fait en\n", "detectant les subdivisions de K5 et de K3,3).\n", "\n", "C'est l'occasion de fixer le vocabulaire CSP que le notebook utilisera ensuite :\n", @@ -263,19 +263,19 @@ "- **Domaine** : l'ensemble des couleurs disponibles (on ne le borne pas a priori — les algorithmes l'etendent au besoin).\n", "- **Contraintes** : pour chaque arete (u, v), la contrainte binaire couleur(u) != couleur(v).\n", "\n", - "Tout le reste — l'ordre de traitement des sommets, la strategie de choix, la recherche d'optimalite — n'est que\n", - "des politiques differentes pour explorer ce meme probleme.\n", + "Tout le reste — l'ordre de traitement des sommets, la stratégie de choix, la recherche d'optimalité — n'est que\n", + "des politiques différentes pour explorer ce même problème.\n", "\n", "\n", "**Pourquoi ce graphe plutot qu'un autre ?** Quatre raisons pedagogiques : (1) il est **planaire** — le theoreme\n", "des quatre couleurs garantit que 4 couleurs suffisent, ce qui donne une borne superieure connue a l'avance pour\n", - "verifier les heuristiques ; (2) il est suffisamment **asymetrique** (degres de 2 a 9) pour que l'ordre de traitement\n", - "du greedy fasse reellement varier le resultat — c'est la lecon centrale de la section 3 ; (3) il est assez petit\n", - "(18 sommets) pour que CP-SAT prouve l'optimalite en quelques dizaines de millisecondes ; et (4) sa realite\n", + "vérifier les heuristiques ; (2) il est suffisamment **asymetrique** (degrés de 2 a 9) pour que l'ordre de traitement\n", + "du greedy fasse reellement varier le résultat — c'est la lecon centrale de la section 3 ; (3) il est assez petit\n", + "(18 sommets) pour que CP-SAT prouve l'optimalité en quelques dizaines de millisecondes ; et (4) sa realite\n", "geographique rend chaque affectation **verifiable a l'oeil** sur la carte finale.\n", "\n", "Ce triplet — borne planaire connue, asymetrie suffisante, taille resolvable — est exactement ce qui fait un bon\n", - "terrain d'experience pour comparer des heuristiques a un solveur exact." + "terrain d'expérience pour comparer des heuristiques a un solveur exact." ] }, { @@ -399,14 +399,14 @@ "source": [ "### Interpretation : structure du graphe\n", "\n", - "La mesure de la cellule precedente donne les **18 sommets, 37 aretes** du sous-ensemble de departements retenu.\n", + "La mesure de la cellule précédente donne les **18 sommets, 37 aretes** du sous-ensemble de departements retenu.\n", "Trois chiffres structurent la suite :\n", "\n", "| Mesure | Valeur | Ce qu'elle annonce |\n", "|---|---|---|\n", - "| **Degre max** | 9 (Seine-et-Marne) | Sommet le plus contraint : 9 voisins, donc 9 couleurs interdites quand on le colorera — candidat naturel pour etre traite en premier (strategie de DSATUR) |\n", - "| **Degre min** | 2 (Nord) | Sommet le plus libre : il garde presque toutes ses options jusqu'au bout |\n", - "| **Degre moyen** | 4.1 | Un graphe localement peu dense : la moyenne est loin du maximal 9 |\n", + "| **Degré max** | 9 (Seine-et-Marne) | Sommet le plus contraint : 9 voisins, donc 9 couleurs interdites quand on le colorera — candidat naturel pour etre traite en premier (stratégie de DSATUR) |\n", + "| **Degré min** | 2 (Nord) | Sommet le plus libre : il garde presque toutes ses options jusqu'au bout |\n", + "| **Degré moyen** | 4.1 | Un graphe localement peu dense : la moyenne est loin du maximal 9 |\n", "\n", "La planarite (``Planaire : True``) est la propriete la plus importante : elle garantit par le theoreme des quatre\n", "couleurs qu'une coloration a **4 couleurs** existe — c'est la borne superieure que greedy et DSATUR vont chacun\n", @@ -535,7 +535,7 @@ "| **Domaines** $D_i$ | Ensemble de couleurs disponibles | $\\{0, 1, \\ldots, k-1\\}$ |\n", "| **Contraintes** $C$ | Deux sommets adjacents ont des couleurs différentes | $c(u) \\neq c(v)$ pour chaque arete $(u, v)$ |\n", "\n", - "Nous allons resoudre ce CSP avec trois approches de complexite croissante." + "Nous allons résoudre ce CSP avec trois approches de complexité croissante." ] }, { @@ -562,7 +562,7 @@ "2. Pour chaque sommet, attribuer la **plus petite couleur** qui n'est pas déjà utilisee par un voisin\n", "\n", "**Proprietes** :\n", - "- Complexite : $O(\\vert V\\vert + \\vert E\\vert)$ -- très rapide\n", + "- Complexité : $O(\\vert V\\vert + \\vert E\\vert)$ -- très rapide\n", "- Garantie : utilise au plus $\\Delta(G) + 1$ couleurs, ou $\\Delta(G)$ est le degré maximum\n", "- Pas optimal en general : le résultat depend de l'ordre de parcours des sommets\n", "\n", @@ -574,18 +574,18 @@ " couleur[v] = plus petit entier >= 0 absent de couleurs_voisins\n", "```\n", "\n", - "**Pourquoi « glouton » ?** Parce que l'algorithme prend, a chaque etape, la decision locale immédiate : donner au\n", + "**Pourquoi « glouton » ?** Parce que l'algorithme prend, a chaque étape, la decision locale immédiate : donner au\n", "sommet courant la plus petite couleur disponible, sans jamais remettre en cause les choix passes. C'est la\n", - "definition meme d'une strategie gloutonne — et sa garantie est faible : avec un ordre defavorable, le compte peut\n", + "definition même d'une stratégie gloutonne — et sa garantie est faible : avec un ordre defavorable, le compte peut\n", "exceder le nombre chromatique (la section suivante le mesure sur nos departements : 4 ou 5 couleurs selon l'ordre,\n", "pour un optimum de 4).\n", "\n", "Deux proprietes utiles a retenir pour la suite :\n", "\n", - "- **Complexite** : un seul passage sur les aretes — $O(V + E)$ — ce qui en fait l'algorithme le plus rapide de ce notebook —\n", - " la section 6 mesure ce cout en millisecondes et le confronte aux deux autres approches.\n", - "- **Borne theorique** : dans le pire des cas, le greedy n'excede jamais $\\Delta(G) + 1$ couleurs, ou $\\Delta(G)$\n", - " est le degre maximal du graphe — une borne universelle, mais tres relachee en pratique." + "- **Complexité** : un seul passage sur les aretes — $O(V + E)$ — ce qui en fait l'algorithme le plus rapide de ce notebook —\n", + " la section 6 mesure ce coût en millisecondes et le confronte aux deux autres approches.\n", + "- **Borne théorique** : dans le pire des cas, le greedy n'excede jamais $\\Delta(G) + 1$ couleurs, ou $\\Delta(G)$\n", + " est le degré maximal du graphe — une borne universelle, mais très relachee en pratique." ] }, { @@ -711,15 +711,15 @@ "source": [ "### Impact de l'ordre des sommets\n", "\n", - "La cellule qui precede a applique greedy **dans l'ordre d'insertion** (l'ordre par defaut du graphe) : resultat,\n", - "**4 couleurs** et une affectation validee (``Valide : True``). Le parcours montre une propriete caracteristique du\n", + "La cellule qui precede a applique greedy **dans l'ordre d'insertion** (l'ordre par defaut du graphe) : résultat,\n", + "**4 couleurs** et une affectation validee (``Valide : True``). Le parcours montre une propriete caractéristique du\n", "greedy : les premiers sommets colores — Paris, Yvelines, Seine-et-Marne en **couleur 0** — capturent les positions\n", "les plus disputees du graphe avant qu'elles ne se referment.\n", "\n", - "La cellule suivante teste l'hypothese centrale de cette section : **ce resultat depend-il de l'ordre choisi ?**\n", - "Elle rejoue greedy sur cinq ordres differents et compare les comptes de couleurs. C'est le point de depart de la\n", - "comparaison des algorithmes : si l'ordre change le resultat, alors un algorithme deterministe mais naif n'est pas\n", - "une reponse stable au probleme de coloration.\n" + "La cellule suivante teste l'hypothèse centrale de cette section : **ce résultat depend-il de l'ordre choisi ?**\n", + "Elle rejoue greedy sur cinq ordres différents et compare les comptes de couleurs. C'est le point de départ de la\n", + "comparaison des algorithmes : si l'ordre change le résultat, alors un algorithme déterministe mais naïf n'est pas\n", + "une reponse stable au problème de coloration.\n" ] }, { @@ -825,13 +825,13 @@ "| Ordre | Couleurs | Lecture |\n", "|---|---|---|\n", "| Defaut | **4** | L'ordre d'insertion du graphe tombe bien |\n", - "| Aleatoire (seed 1) | **5** | Un ordre arbitraire coute une couleur |\n", - "| Aleatoire (seed 2) | **5** | Le hasard coute une couleur, stablement |\n", - "| Degre decroissant | **4** | Trier les sommets par degre decroissant preserve l'optimum |\n", - "| Degre croissant | **5** | Partir des sommets les moins contraints degrade le compte |\n", + "| Aléatoire (seed 1) | **5** | Un ordre arbitraire coute une couleur |\n", + "| Aléatoire (seed 2) | **5** | Le hasard coute une couleur, stablement |\n", + "| Degré decroissant | **4** | Trier les sommets par degré decroissant preserve l'optimum |\n", + "| Degré croissant | **5** | Partir des sommets les moins contraints degrade le compte |\n", "\n", - "La lecon est double. D'abord, les deux ordres aleatoires (seed 1 et seed 2) **rendent 5 couleurs tous les deux** —\n", - "le surcout du hasard n'est pas un epiphenomene d'une graine particuliere. Ensuite, l'ordre par **degre decroissant**\n", + "La lecon est double. D'abord, les deux ordres aléatoires (seed 1 et seed 2) **rendent 5 couleurs tous les deux** —\n", + "le surcout du hasard n'est pas un epiphenomene d'une graine particuliere. Ensuite, l'ordre par **degré decroissant**\n", "est le bon reflexe : colorer en premier les sommets qui ont le plus de voisins reserve leurs couleurs avant que les\n", "options ne se reduisent. C'est l'intuition que DSATUR va systematiser dans la section suivante.\n" ] @@ -898,7 +898,7 @@ "\n", "### Principe de l'algorithme\n", "\n", - "**DSATUR** (Degree of Saturation) est un algorithme propose par Brelaz (1979). Au lieu de fixer un ordre statique des sommets, DSATUR choisit **dynamiquement** le prochain sommet a colorier en fonction de l'etat courant.\n", + "**DSATUR** (Degree of Saturation) est un algorithme propose par Brelaz (1979). Au lieu de fixer un ordre statique des sommets, DSATUR choisit **dynamiquement** le prochain sommet a colorier en fonction de l'état courant.\n", "\n", "**Saturation** d'un sommet $v$ : nombre de **couleurs distinctes** déjà attribuees aux voisins de $v$.\n", "\n", @@ -920,19 +920,19 @@ "| Ordre | Statique (fixe avant l'algorithme) | Dynamique (recalcule a chaque étape) |\n", "| Critere | Position dans la liste | Saturation + degré |\n", "| Résultat | Depend de l'heuristique d'ordre | Généralement meilleur ou egal |\n", - "| Complexite | $O(\\vert V\\vert + \\vert E\\vert)$ | $O(\\vert V\\vert^2)$ avec implementation naive |\n", + "| Complexité | $O(\\vert V\\vert + \\vert E\\vert)$ | $O(\\vert V\\vert^2)$ avec implementation naive |\n", "\n", "DSATUR est une forme de greedy adaptatif : il applique la stratégie \"fail-first\" des CSP en traitant d'abord les sommets les plus contraints a chaque instant.\n", "\n", "**Ce qui change fondamentalement par rapport au greedy** : l'ordre n'est plus fixe a l'avance — DSATUR le construit\n", - "*pendant* la coloration, en choisissant a chaque etape le sommet le plus « urgent ». L'urgence se mesure par la\n", - "**saturation** (nombre de couleurs deja interdites par les voisins colores), departagee par le **degre** restant.\n", + "*pendant* la coloration, en choisissant a chaque étape le sommet le plus « urgent ». L'urgence se mesure par la\n", + "**saturation** (nombre de couleurs déjà interdites par les voisins colores), departagee par le **degré** restant.\n", "\n", "La propriete la plus remarquable de DSATUR est qu'il est **exact sur les graphes bipartis** (il en trouve toujours\n", "le nombre chromatique 2) et qu'il se demarque sur les graphes planaires : c'est historiquement l'algorithme qui a\n", "fourni les meilleures colorations de cartes avant l'ere des solveurs exacts. Comme Brelaz l'a montre dans son\n", "article de 1979, l'intuition du « sommet le plus contraint d'abord » est remarquablement efficace — d'autant plus\n", - "que son cout n'est qu'en $O(V^2)$, a peine plus cher que le greedy." + "que son coût n'est qu'en $O(V^2)$, a peine plus cher que le greedy." ] }, { @@ -1064,13 +1064,13 @@ "L'interpretation a l'oeil des affectations ne suffit pas : pour comprendre **pourquoi** DSATUR obtient 4 couleurs,\n", "la cellule suivante rejoue l'algorithme pas a pas sur les departements.\n", "\n", - "La trace affiche, pour chacune des **18 etapes** (une par sommet) : le sommet choisi, sa **saturation** (nombre de\n", - "couleurs deja utilisees par ses voisins colores), son **degre** (nombre de voisins au total), et la **couleur**\n", + "La trace affiche, pour chacune des **18 étapes** (une par sommet) : le sommet choisi, sa **saturation** (nombre de\n", + "couleurs déjà utilisees par ses voisins colores), son **degré** (nombre de voisins au total), et la **couleur**\n", "attribuee.\n", "\n", - "Regle de choix de DSATUR a retenir pour lire la trace : a chaque etape, il prend le sommet non colore de\n", - "**saturation maximale**, et departage par le **degre maximal**. La saturation mesure l'urgence reelle (les couleurs\n", - "interdites par les voisins deja colores), le degre anticipe les choix futurs.\n" + "Règle de choix de DSATUR a retenir pour lire la trace : a chaque étape, il prend le sommet non colore de\n", + "**saturation maximale**, et departage par le **degré maximal**. La saturation mesure l'urgence reelle (les couleurs\n", + "interdites par les voisins déjà colores), le degré anticipe les choix futurs.\n" ] }, { @@ -1188,22 +1188,22 @@ "source": [ "### Interpretation : trace DSATUR\n", "\n", - "La trace confirme le mecanisme et montre son intelligence locale.\n", + "La trace confirme le mécanisme et montre son intelligence locale.\n", "\n", - "- **Etape 1** : Seine-et-Marne (saturation 0, degre 9) prend la couleur 0 — il n'a aucun voisin encore colore,\n", - " on le choisit pour son degre maximum.\n", - "- **Etapes 2-3** : Oise puis Aisne, voisins de Seine-et-Marne, entrent en **saturation 1 puis 2** : leur voisin\n", - " colore leur a deja interdit les couleurs 0 puis 0-1 ; ils prennent les couleurs 1 et 2.\n", - "- **Etapes 4-12** : la saturation monte a **2 sur toute la couronne** de Seine-et-Marne (Marne, Somme, Aube, Yonne, Loiret,\n", + "- **Étape 1** : Seine-et-Marne (saturation 0, degré 9) prend la couleur 0 — il n'a aucun voisin encore colore,\n", + " on le choisit pour son degré maximum.\n", + "- **Étapes 2-3** : Oise puis Aisne, voisins de Seine-et-Marne, entrent en **saturation 1 puis 2** : leur voisin\n", + " colore leur a déjà interdit les couleurs 0 puis 0-1 ; ils prennent les couleurs 1 et 2.\n", + "- **Étapes 4-12** : la saturation monte a **2 sur toute la couronne** de Seine-et-Marne (Marne, Somme, Aube, Yonne, Loiret,\n", " Essonne, Val-de-Marne, Seine-Saint-Denis, Hauts-de-Seine). Chaque sommet colore se repercute sur ses voisins :\n", - " c'est la propagation de contrainte caracteristique des colorations de cartes denses.\n", - "- **Etape 13** : Paris ouvre une couleur neuve (**3**) : a ce stade ses trois voisins possibles sont deja colores,\n", + " c'est la propagation de contrainte caractéristique des colorations de cartes denses.\n", + "- **Étape 13** : Paris ouvre une couleur neuve (**3**) : a ce stade ses trois voisins possibles sont déjà colores,\n", " sa saturation atteint 3 — il ne peut plus prendre ni 0, ni 1, ni 2.\n", - "- **Etapes 14-18** : la fin du parcours colorie la peripherie (Yvelines, Val-d'Oise, Eure, Eure-et-Loir,\n", + "- **Étapes 14-18** : la fin du parcours colorie la peripherie (Yvelines, Val-d'Oise, Eure, Eure-et-Loir,\n", " Nord) sans jamais depasser les 4 couleurs existantes.\n", "\n", - "Au total, la trace mene aux memes **4 couleurs** que greedy, mais par un chemin plus delibere : chaque choix est\n", - "dicte par la contrainte la plus pressante, pas par l'ordre du hasard. La question de l'optimalite — est-ce que 4 est\n", + "Au total, la trace mene aux mêmes **4 couleurs** que greedy, mais par un chemin plus delibere : chaque choix est\n", + "dicte par la contrainte la plus pressante, pas par l'ordre du hasard. La question de l'optimalité — est-ce que 4 est\n", "le minimum possible ? — reste ouverte ; c'est CP-SAT qui la tranchera plus bas.\n" ] }, @@ -1262,12 +1262,12 @@ "source": [ "### Comparaison Greedy vs DSATUR sur le graphe de Petersen\n", "\n", - "Passons du cas reel (les departements) a un graphe de reference de la theorie des graphes : **le graphe de Petersen**,\n", - "10 sommets reguliers de degre 3. Sa propriete la plus connue est son nombre chromatique : **chi = 3** (il se colore\n", + "Passons du cas réel (les departements) a un graphe de reference de la théorie des graphes : **le graphe de Petersen**,\n", + "10 sommets reguliers de degré 3. Sa propriete la plus connue est son nombre chromatique : **chi = 3** (il se colore\n", "en 3 couleurs, pas en 2 — il contient des cycles impairs, donc le minimum est au moins 3).\n", "\n", "La cellule suivante confronte les trois approches sur ce graphe et affiche la valeur optimale ``chi = 3`` comme point\n", - "de comparaison. C'est le test le plus net possible de l'optimalite des heuristiques : si greedy et DSATUR atteignent\n", + "de comparaison. C'est le test le plus net possible de l'optimalité des heuristiques : si greedy et DSATUR atteignent\n", "3, ils atteignent l'optimum ; sinon, l'ecart est directement lisible.\n" ] }, @@ -1378,19 +1378,19 @@ "source": [ "### Interpretation : Petersen\n", "\n", - "Le resultat est net : **les trois approches atteignent l'optimum chi = 3** sur le graphe de Petersen, et DSATUR\n", - "comme le greedy par degre decroissant egalent la borne du nombre chromatique affiche par la reference.\n", + "Le résultat est net : **les trois approches atteignent l'optimum chi = 3** sur le graphe de Petersen, et DSATUR\n", + "comme le greedy par degré decroissant egalent la borne du nombre chromatique affiche par la reference.\n", "\n", "Pourquoi si facile ici alors que la France a demande 4 couleurs ? Parce que Petersen est un graphe **regulier de\n", - "degre 3** : les trois ordres raisonnables (defaut, degre decroissant, DSATUR) traitent des sommets tous equivalents\n", - "en contrainte, et la structure symetrique du graphe laisse au greedy peu d'occasions de se tromper. Le cas francais,\n", - "lui, melange des degres de 2 a 9 : l'asymetrie est justement l'endroit ou l'ordre fait la difference.\n", + "degré 3** : les trois ordres raisonnables (defaut, degré decroissant, DSATUR) traitent des sommets tous equivalents\n", + "en contrainte, et la structure symetrique du graphe laisse au greedy peu d'occasions de se tromper. Le cas français,\n", + "lui, melange des degrés de 2 a 9 : l'asymetrie est justement l'endroit ou l'ordre fait la différence.\n", "\n", "La figure a deux axes confirme visuellement la coloration : chacune des deux moities du graphe (le pentagone\n", "exterieur et l'etoile interieure, la forme classique de Petersen) est coloree sans conflit avec 3 teintes.\n", "\n", "Le prochain defi n'est plus de trouver *une* coloration valide, mais la **moins riche possible** — c'est un\n", - "probleme d'optimisation, le terrain de CP-SAT.\n" + "problème d'optimisation, le terrain de CP-SAT.\n" ] }, { @@ -1411,11 +1411,11 @@ "\n", "## 5. Approche 3 : OR-Tools CP-SAT (~8 min)\n", "\n", - "Pour **prouver** l'optimalite, nous utilisons le solveur **CP-SAT** de Google OR-Tools. Contrairement aux heuristiques, CP-SAT explore systematiquement l'espace de recherche et peut garantir que la solution trouvee utilise le nombre minimum de couleurs.\n", + "Pour **prouver** l'optimalité, nous utilisons le solveur **CP-SAT** de Google OR-Tools. Contrairement aux heuristiques, CP-SAT explore systematiquement l'espace de recherche et peut garantir que la solution trouvee utilise le nombre minimum de couleurs.\n", "\n", - "### Modelisation CP-SAT\n", + "### Modélisation CP-SAT\n", "\n", - "| Élément | Modelisation |\n", + "| Élément | Modélisation |\n", "|---------|-------------|\n", "| Variable $x_v$ | `model.new_int_var(0, k-1, f'color_{v}')` pour chaque sommet $v$ |\n", "| Contrainte | `model.add(x_u != x_v)` pour chaque arete $(u, v)$ |\n", @@ -1423,15 +1423,15 @@ "\n", "Pour minimiser $k$, nous introduisons une variable `max_color` et contraignons chaque `x_v <= max_color`, puis nous minimisons `max_color`.\n", "\n", - "**Le changement de nature du probleme** : trouver une coloration valide est facile (le greedy y arrive en\n", - "millisecondes) ; *prouver* qu'un compte donne est le minimum possible est un probleme bien plus dur. Decider si un\n", + "**Le changement de nature du problème** : trouver une coloration valide est facile (le greedy y arrive en\n", + "millisecondes) ; *prouver* qu'un compte donne est le minimum possible est un problème bien plus dur. Decider si un\n", "graphe se colore avec k couleurs est NP-complet des que k >= 3 — c'est une consequence du theoreme de\n", - "Karp (1972), qui classe la k-coloration parmi les 21 problemes NP-complets fondateurs.\n", + "Karp (1972), qui classe la k-coloration parmi les 21 problèmes NP-complets fondateurs.\n", "\n", "Cette durete n'a pas de consequence pratique sur un graphe de 18 sommets, mais elle explique ce que CP-SAT fait\n", "dans la section 6 : la recherche exacte explore l'espace des colorations en **prouvant** au passage qu'une\n", "solution a 3 couleurs n'existe pas. La contrepartie est que le temps de calcul peut exploser quand le graphe\n", - "grossit — c'est precisement le cout que le benchmark de la fin mesurera, et la raison pour laquelle une\n", + "grossit — c'est précisément le coût que le benchmark de la fin mesurera, et la raison pour laquelle une\n", "heuristique comme DSATUR reste l'outil quotidien." ] }, @@ -1590,18 +1590,18 @@ "### Resolution optimale par CP-SAT\n", "\n", "Jusqu'ici, greedy et DSATUR ont **construit** une coloration valide — et ont trouve 4 couleurs — mais rien ne prouve\n", - "que 4 est le **minimum possible**. Le nombre chromatique exact d'un graphe est un probleme d'optimisation\n", + "que 4 est le **minimum possible**. Le nombre chromatique exact d'un graphe est un problème d'optimisation\n", "NP-difficile : une coloration en k couleurs se verifie polynomialement, la *trouver* exige une recherche de decision\n", "combinatoire.\n", "\n", - "CP-SAT (le solveur de contraintes d'OR-Tools) attaque ce probleme par la **programmation par contraintes** :\n", + "CP-SAT (le solveur de contraintes d'OR-Tools) attaque ce problème par la **programmation par contraintes** :\n", "\n", "- **Variables** : pour chaque sommet, une variable entiere color[v] dans {0, ..., k-1}.\n", - "- **Contraintes** : pour chaque arete, color[u] != color[v] (contrainte de difference — le solveur la propage par\n", - " des raisonnements d'all-different locaux).\n", + "- **Contraintes** : pour chaque arete, color[u] != color[v] (contrainte de différence — le solveur la propage par\n", + " des raisonnements d'all-différent locaux).\n", "- **Objectif** : minimiser k, en redemarrant la recherche tant que la preuve d'impossibilite n'est pas obtenue.\n", "\n", - "La cellule suivante applique ce modele aux departements et affiche le verdict : statut de la preuve (``OPTIMAL``),\n", + "La cellule suivante applique ce modèle aux departements et affiche le verdict : statut de la preuve (``OPTIMAL``),\n", "temps, et statistiques de recherche (branches explorees, conflits detectes).\n" ] }, @@ -1693,7 +1693,7 @@ "tags": [] }, "source": [ - "### Interpretation : resultat CP-SAT\n", + "### Interpretation : résultat CP-SAT\n", "\n", "Le solveur tranche la question laissee ouverte : **chi(G) = 4 est le nombre chromatique exact** des departements.\n", "La ligne ``Statut : OPTIMAL`` a une importance epistemique : elle ne signifie pas « on a essaye 4 et ca marche »\n", @@ -1702,14 +1702,14 @@ "\n", "Les statistiques de la preuve :\n", "\n", - "- **78.0 ms** : le probleme est petit (18 sommets, 37 aretes) — CP-SAT le resout en un eclair, c'est l'echelle de\n", + "- **78.0 ms** : le problème est petit (18 sommets, 37 aretes) — CP-SAT le resout en un eclair, c'est l'echelle de\n", " confort de ce solveur.\n", "- **254 branches explorees** : la taille de l'arbre de recherche effectivement visite pour fermer la preuve.\n", "- **1 conflit detecte** : un seul raisonnement de contradiction a suffi a elaguer tout un pan de l'espace — c'est la\n", " force de la propagation de contraintes face a une simple enumeration.\n", "\n", - "On obtient donc le meme compte — **4 couleurs** — que greedy et DSATUR, mais avec une garantie que les heuristiques\n", - "ne peuvent pas fournir : l'optimalite. La contrepartie de cette garantie est le cout : ce que CP-SAT paie en temps de\n", + "On obtient donc le même compte — **4 couleurs** — que greedy et DSATUR, mais avec une garantie que les heuristiques\n", + "ne peuvent pas fournir : l'optimalité. La contrepartie de cette garantie est le coût : ce que CP-SAT paie en temps de\n", "recherche quand le graphe grossit, c'est exactement ce que le benchmark final va mesurer.\n" ] }, @@ -1768,13 +1768,13 @@ "source": [ "### Enumeration des solutions sur un petit graphe\n", "\n", - "Une coloration raisonnable n'est *pas* unique : deux colorations qui ne different que par une permutation globale\n", + "Une coloration raisonnable n'est *pas* unique : deux colorations qui ne différent que par une permutation globale\n", "des couleurs sont aussi valides l'une que l'autre, et il existe souvent bien plus de colorations distinctes que de\n", - "« schemas » conceptuellement differents.\n", + "« schemas » conceptuellement différents.\n", "\n", "La cellule suivante enumere **toutes** les colorations valides du graphe de Petersen en 3 couleurs (le solveur est\n", "configure en mode enumeration : chaque solution trouvee relance la recherche pour la suivante). C'est un exercice de\n", - "comptage : combien de solutions, et a quoi ressemble la premiere ?\n" + "comptage : combien de solutions, et a quoi ressemble la première ?\n" ] }, { @@ -1841,8 +1841,8 @@ "source": [ "### Interpretation : enumeration\n", "\n", - "Le solveur denombre **40 colorations en 3 couleurs** du graphe de Petersen, en **19.9 ms**. La premiere solution\n", - "affichee est un dictionnaire {sommet: couleur} : chaque entier de 0 a 9 est un sommet, chaque valeur une teinte.\n", + "Le solveur denombre **40 colorations en 3 couleurs** du graphe de Petersen, en **19.9 ms**. La première solution\n", + "affichée est un dictionnaire {sommet: couleur} : chaque entier de 0 a 9 est un sommet, chaque valeur une teinte.\n", "\n", "Deux remarques sur ce nombre :\n", "\n", @@ -1850,11 +1850,11 @@ " formellement distinctes mais structurellement identiques. Les 40 solutions integrent cette multiplicite — le\n", " denombrement brut sur-estime donc la diversite reelle par ce facteur de symetrie.\n", "2. **Le comptage est un diagnostic.** Si le solveur n'avait trouve qu'une poignee de solutions, on soupconnerait une\n", - " contrainte cachee ou une erreur de modele ; l'ordre de grandeur ici confirme un espace de solutions raisonnable\n", + " contrainte cachee ou une erreur de modèle ; l'ordre de grandeur ici confirme un espace de solutions raisonnable\n", " et la validite de la formulation.\n", "\n", - "C'est aussi une demonstration de la flexibilite du modele : le meme solveur qui *prouve l'optimalite* sur un graphe\n", - "**enumere** sur l'autre, sans changer une ligne de la formulation — seule la strategie de recherche differe (arret a\n", + "C'est aussi une demonstration de la flexibilite du modèle : le même solveur qui *prouve l'optimalité* sur un graphe\n", + "**enumere** sur l'autre, sans changer une ligne de la formulation — seule la stratégie de recherche differe (arret a\n", "l'optimum contre exploration exhaustive)." ] }, @@ -1876,16 +1876,16 @@ "\n", "## 6. Benchmark et visualisation (~6 min)\n", "\n", - "Comparons maintenant les trois algorithmes sur des graphes de taille croissante. Nous utilisons des **graphes aleatoires** $G(n, p)$ (modèle d'Erdos-Renyi) ou chaque arete existe avec probabilite $p$.\n", + "Comparons maintenant les trois algorithmes sur des graphes de taille croissante. Nous utilisons des **graphes aléatoires** $G(n, p)$ (modèle d'Erdos-Renyi) ou chaque arete existe avec probabilite $p$.\n", "\n", - "**Pourquoi des graphes aleatoires G(n, p) ?** Le modele d'Erdos-Renyi est le banc d'essai standard de la theorie\n", - "des graphes : chaque paire de sommets est reliee independamment avec une probabilite p fixe, augmenter\n", + "**Pourquoi des graphes aléatoires G(n, p) ?** Le modèle d'Erdos-Renyi est le banc d'essai standard de la théorie\n", + "des graphes : chaque paire de sommets est reliee indépendamment avec une probabilite p fixe, augmenter\n", "n fait grossir a la fois le nombre de sommets et la densite du graphe — un double durcissement qui exerce\n", "realement les trois algorithmes.\n", "\n", "energie. Les trois metriques rendues par la cellule suivante se lisent ensemble : **greedy** joue la vitesse pure,\n", - "**DSATUR** joue la qualite a cout quasi nul, **CP-SAT** joue l'optimalite a cout exponentiel. C'est ce compromis\n", - "qui structure la conclusion : quel outil choisir quand on ne connait pas la taille du probleme a l'avance ?" + "**DSATUR** joue la qualité a coût quasi nul, **CP-SAT** joue l'optimalité a coût exponentiel. C'est ce compromis\n", + "qui structure la conclusion : quel outil choisir quand on ne connait pas la taille du problème a l'avance ?" ] }, { @@ -2009,7 +2009,7 @@ "Le tableau est bref mais unanime : les trois algorithmes rendent **4 couleurs** sur les departements, tous valides,\n", "tous optimaux. Les temps sont anecdotiques a cette echelle (0.03 ms pour Welsh-Powell, 0.08 ms pour DSATUR, 20.42 ms pour CP-SAT) mais leur *rapport* est parlant : le solveur exact paie sa preuve environ **680 fois le temps du greedy** (20.42 / 0.03 ~ 680).\n", "\n", - "Le point important n'est pas la vitesse ici, c'est la qualite : quand le probleme est facile (graphe planaire de\n", + "Le point important n'est pas la vitesse ici, c'est la qualité : quand le problème est facile (graphe planaire de\n", "taille modeste), la recherche exacte n'ajoute rien — c'est le cas de couverture suivant qui decide." ] }, @@ -2027,9 +2027,9 @@ "tags": [] }, "source": [ - "### Benchmark sur des graphes aleatoires de taille croissante\n", + "### Benchmark sur des graphes aléatoires de taille croissante\n", "\n", - "Pour mesurer le prix de l'optimalite, la cellule suivante genere des graphes aleatoires G(n, p) — chaque paire\n", + "Pour mesurer le prix de l'optimalité, la cellule suivante genere des graphes aléatoires G(n, p) — chaque paire\n", "de sommets est reliee avec une probabilite p fixe, dont la valeur apparaitt dans l'output (G(n, 0.3)) —\n", "pour **n de 20 a 200 sommets**, et rejoue sur chacun les trois\n", "approches.\n", @@ -2180,7 +2180,7 @@ "source": [ "### Lecture des courbes du benchmark\n", "\n", - "Les deux graphiques produits par la cellule precedente se lisent ensemble :\n", + "Les deux graphiques produits par la cellule précédente se lisent ensemble :\n", "\n", "- **Gauche — nombre de couleurs en fonction de n** : attire l'attention sur les heuristiques qui s'ecartent de la\n", " valeur exacte quand le graphe grossit. DSATUR doit rester colle a la courbe optimale, greedy s'en eloigner au fur\n", @@ -2188,9 +2188,9 @@ "- **Droite — temps de calcul en fonction de n** (echelle log) : le prix de chaque approche. C'est la que l'explosion\n", " de CP-SAT doit devenir visible.\n", "\n", - "Attention au piege de lecture : plus de couleurs *et* plus de temps n'ont pas le meme statut. Une heuristique lente\n", + "Attention au piege de lecture : plus de couleurs *et* plus de temps n'ont pas le même statut. Une heuristique lente\n", "doit faire preuve d'un meilleur compte pour etre utile ; une heuristique rapide peut se permettre d'etre imparfaite.\n", - "Le verdict se prend colonne par colonne sur le tableau de la cellule precedente.\n" + "Le verdict se prend colonne par colonne sur le tableau de la cellule précédente.\n" ] }, { @@ -2287,24 +2287,24 @@ "\n", "Trois enseignements se degagent.\n", "\n", - "1. **CP-SAT est precis, greedy est en retard.** Partout, le solveur rend le compte le plus bas (a n=40 il rend 6\n", + "1. **CP-SAT est précis, greedy est en retard.** Partout, le solveur rend le compte le plus bas (a n=40 il rend 6\n", " quand les heuristiques en donnent 7 et 8 ; a n=100 il rend 10 contre 12 pour greedy). La courbe de gauche du\n", " graphique montre l'ecart qui se creuse : la recherche exacte ne paie pas que du confort, elle gagne reellement\n", " des couleurs.\n", "\n", - "2. **DSATUR comprime l'essentiel du gain a cout derisoire.** Sur les sept tailles, DSATUR ne depasse jamais greedy\n", + "2. **DSATUR comprime l'essentiel du gain a coût derisoire.** Sur les sept tailles, DSATUR ne depasse jamais greedy\n", " de plus de 3 couleurs (22 contre 19 a n=200) et il reste sous les 1 ms jusqu'a n=60 (0.7 ms), puis 8 ms a n=200 —\n", - " soit un cout quasi nul face aux dizaines de secondes de CP-SAT, pour la quasi-totalite du gain de qualite.\n", + " soit un coût quasi nul face aux dizaines de secondes de CP-SAT, pour la quasi-totalite du gain de qualité.\n", "\n", "3. **L'explosion de CP-SAT est brutale — et se lit une fois connue la limite de temps.** De **21.5 ms** a n=20, il passe a **7 629.5 ms** a n=60 : environ 350 fois plus cher entre n=20 et n=60,\n", " soit 40 sommets de plus. A n=60, le solveur termine encore naturellement (7 629.5 ms, sous la limite) ; a partir de **n=80**, toutes les lignes CP-SAT plafonnent autour de **10 000 ms** : c'est la limite de temps imposee par la cellule\n", " (time_limit) qui coupe la recherche, pas une fin naturelle — et c'est la raison pour laquelle la colonne couleurs\n", - " de CP-SAT continue de progresser apres : un solveur interrompu rend la meilleure solution trouvee, pas l'optimum\n", + " de CP-SAT continue de progresser après : un solveur interrompu rend la meilleure solution trouvee, pas l'optimum\n", " prouve.\n", "\n", "**Conclusion de la section** : on ne connait pas la taille d'un vrai graphe a l'avance. Le reflexe standard est de\n", - "lancer DSATUR en premier (qualite stable, cout quasi nul), et de reserver CP-SAT aux graphes dont on sait\n", - "d'avance qu'ils sont petits — ou la preuve d'optimalite vaut ses millisecondes.\n" + "lancer DSATUR en premier (qualité stable, coût quasi nul), et de reserver CP-SAT aux graphes dont on sait\n", + "d'avance qu'ils sont petits — ou la preuve d'optimalité vaut ses millisecondes.\n" ] }, { @@ -2323,13 +2323,13 @@ "source": [ "### Visualisation finale : carte des departements\n", "\n", - "Derniere figure du notebook : la carte des 18 departements coloree avec **la coloration optimale prouvee par\n", + "Dernière figure du notebook : la carte des 18 departements coloree avec **la coloration optimale prouvee par\n", "CP-SAT**.\n", "\n", "A la lecture de cette carte :\n", "\n", - "- les **4 teintes** se repartissent sans conflit — chaque frontiere separe des zones de couleurs differentes ;\n", - "- on reconnait sur la carte les resultats vus dans la trace DSATUR : le bloc central (Paris et sa couronne)\n", + "- les **4 teintes** se repartissent sans conflit — chaque frontiere separe des zones de couleurs différentes ;\n", + "- on reconnait sur la carte les résultats vus dans la trace DSATUR : le bloc central (Paris et sa couronne)\n", " s'oppose nettement aux departements peripheriques (Somme, Eure, Loiret, Aube) ;\n", "- la figure est la preuve visuelle finale du theoreme des quatre couleurs sur ce sous-ensemble : une carte reelle\n", " (etant planaire) se colore en 4 couleurs au plus, et les 4 sont ici *necessaires* puisque CP-SAT a prouve\n", @@ -2448,20 +2448,20 @@ "\n", "## 7. Exemple guide\n", "\n", - "### Exemple guide 1 : Colorier les etats americains\n", + "### Exemple guide 1 : Colorier les états americains\n", "\n", - "Construisez un graphe simplifie de 10-12 etats americains contigus (par exemple la region des Grands Lacs : Ohio, Indiana, Illinois, Michigan, Wisconsin, Minnesota, Iowa, Missouri, Kentucky, West Virginia). Appliquez les trois algorithmes et comparez.\n", + "Construisez un graphe simplifie de 10-12 états americains contigus (par exemple la region des Grands Lacs : Ohio, Indiana, Illinois, Michigan, Wisconsin, Minnesota, Iowa, Missouri, Kentucky, West Virginia). Appliquez les trois algorithmes et comparez.\n", "\n", "**Indice** : vous pouvez trouver les adjacences sur Wikipedia (\"list of US states by border\").\n", "\n", - "**Du cours a la pratique** : les trois exemples resolus de cette section reutilisent les fonctions definies plus\n", + "**Du cours a la pratique** : les trois exemples resolus de cette section reutilisent les fonctions définies plus\n", "haut (``greedy_coloring``, ``dsatur_coloring``, ``cpsat_coloring``) sur de **nouveaux graphes** — la region des Grands Lacs\n", - "(11 etats, planaire), l'icosaedre, puis une comparaison Welsh-Powell vs DSATUR sur cinq graphes aleatoires.\n", + "(11 états, planaire), l'icosaedre, puis une comparaison Welsh-Powell vs DSATUR sur cinq graphes aléatoires.\n", "\n", - "La demarche attendue est systematique : (1) construire le graphe des adjacences, (2) appliquer les trois\n", - "approches, (3) comparer le compte de couleurs obtenu a la valeur optimale affichee, (4) ecrire une phrase qui\n", - "explique l'ecart eventuel (ou son absence). Les exercices 1b, 2b et 3b reprennent ces quatre etapes sur des\n", - "graphes que vous construisez vous-meme — la methode compte autant que le resultat." + "La demarche attendue est systématique : (1) construire le graphe des adjacences, (2) appliquer les trois\n", + "approches, (3) comparer le compte de couleurs obtenu a la valeur optimale affichée, (4) ecrire une phrase qui\n", + "explique l'ecart eventuel (ou son absence). Les exercices 1b, 2b et 3b reprennent ces quatre étapes sur des\n", + "graphes que vous construisez vous-même — la méthode compte autant que le résultat." ] }, { @@ -2804,12 +2804,12 @@ "source": [ "### Exemple guide 2 : Borne superieure du greedy et planarite\n", "\n", - "L'icosaedre est le second graphe de reference : 12 sommets, 30 aretes, regulier de degre 5, et **planaire** — le\n", + "L'icosaedre est le second graphe de reference : 12 sommets, 30 aretes, regulier de degré 5, et **planaire** — le\n", "theoreme des quatre couleurs s'applique donc, et une coloration en 4 couleurs doit exister.\n", "\n", "La cellule suivante evalue le pire cas du greedy sur ce graphe : elle compare une coloration gloutonne dans un ordre\n", - "defavorable a l'optimum exact. C'est le test de la borne superieure : meme mal ordonne, le greedy reste-t-il sous la\n", - "garantie 4 ? (L'ordre par defaut d'un graphe regulier etant arbitraire, ce n'est pas forcement le pire cas reel —\n", + "defavorable a l'optimum exact. C'est le test de la borne superieure : même mal ordonne, le greedy reste-t-il sous la\n", + "garantie 4 ? (L'ordre par defaut d'un graphe regulier etant arbitraire, ce n'est pas forcement le pire cas réel —\n", "le notebook mesure ce qui se produit, il n'essaie pas d'exhiber le pire.)\n" ] }, @@ -3101,12 +3101,12 @@ "source": [ "### Exemple guide 3 : Implementer Welsh-Powell et comparer avec DSATUR\n", "\n", - "L'exemple precedent a pose la borne superieure du greedy. Ici, on enrichit la comparaison en implementant\n", - "**Welsh-Powell** (la variante du greedy qui trie les sommets par degre decroissant puis colore chaque sommet avec la\n", - "plus petite couleur disponible — le meme algorithme que la ligne « degre decroissant » du debut du notebook), et on\n", - "le confronte a DSATUR sur **cinq graphes aleatoires**.\n", + "L'exemple précédent a pose la borne superieure du greedy. Ici, on enrichit la comparaison en implementant\n", + "**Welsh-Powell** (la variante du greedy qui trie les sommets par degré decroissant puis colore chaque sommet avec la\n", + "plus petite couleur disponible — le même algorithme que la ligne « degré decroissant » du debut du notebook), et on\n", + "le confronte a DSATUR sur **cinq graphes aléatoires**.\n", "\n", - "La cellule suivante genere cinq graphes G0 a G4 (graines fixees, deterministes) et affiche, pour chacun : le compte\n", + "La cellule suivante genere cinq graphes G0 a G4 (graines fixees, déterministes) et affiche, pour chacun : le compte\n", "de Welsh-Powell (WP), de DSATUR, et l'optimum calcule par CP-SAT. A vous de lire l'ecart : WP est-il systematiquement\n", "battu ? Par combien de couleurs ? Sur quelles graines DSATUR atteint-il l'optimum ?\n" ] @@ -3530,18 +3530,18 @@ "\n", "### Resume des algorithmes\n", "\n", - "| Algorithme | Type | Complexite | Qualite | Garantie |\n", + "| Algorithme | Type | Complexité | Qualité | Garantie |\n", "|------------|------|-----------|---------|----------|\n", "| **Greedy** | Heuristique constructive | $O(V + E)$ | $\\leq \\Delta(G) + 1$ couleurs | Borne superieure |\n", "| **DSATUR** | Heuristique adaptative | $O(V^2)$ | Souvent optimal | Aucune (exact pour bipartis) |\n", - "| **CP-SAT** | Solveur exact | Exponentiel pire cas | Optimal ($\\chi(G)$) | Preuve d'optimalite |\n", + "| **CP-SAT** | Solveur exact | Exponentiel pire cas | Optimal ($\\chi(G)$) | Preuve d'optimalité |\n", "\n", "### Ce que nous avons appris\n", "\n", "1. La **coloration de graphe** est un problème NP-difficile fondamental avec de nombreuses applications\n", - "2. L'**ordre des sommets** a un impact majeur sur la qualite de la coloration gloutonne\n", + "2. L'**ordre des sommets** a un impact majeur sur la qualité de la coloration gloutonne\n", "3. **DSATUR** adapte dynamiquement l'ordre en privilegiant les sommets les plus satures (analogie avec MRV en CSP)\n", - "4. **CP-SAT** garantit l'optimalite mais ne passe pas a l'echelle sur les grands graphes\n", + "4. **CP-SAT** garantit l'optimalité mais ne passe pas a l'echelle sur les grands graphes\n", "5. Le **theoreme des quatre couleurs** borne le nombre chromatique des graphes planaires\n", "\n", "### Pour aller plus loin\n", @@ -3560,13 +3560,13 @@ "\n", "**Ce qu'il faut retenir du notebook en trois lignes** :\n", "\n", - "1. Une coloration valide se trouve facilement (greedy), mais son cout depend de l'ordre choisi — l'ordre par degre\n", + "1. Une coloration valide se trouve facilement (greedy), mais son coût depend de l'ordre choisi — l'ordre par degré\n", " decroissant est le reflexe sur-domine par DSATUR, qui choisit dynamiquement le sommet le plus contraint.\n", "2. Trouver le **nombre chromatique exact** est NP-difficile : seul un solveur exact comme CP-SAT peut *prouver*\n", - " l'optimalite (chi = 4 pour les departements, verifie en 85.2 ms), contre des dizaines de secondes des que le\n", + " l'optimalité (chi = 4 pour les departements, verifie en 85.2 ms), contre des dizaines de secondes des que le\n", " graphe atteint quelques dizaines de sommets.\n", "3. Le choix de l'outil se prend donc en **connaissant la taille** : DSATUR en premier systematiquement, CP-SAT\n", - " reserve aux petits graphes dont la preuve d'optimalite vaut le temps de calcul." + " reserve aux petits graphes dont la preuve d'optimalité vaut le temps de calcul." ] } ], diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20-SudokuBenchmark-Python.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20-SudokuBenchmark-Python.ipynb index b9cfb8806b7..a113e326d56 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20-SudokuBenchmark-Python.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20-SudokuBenchmark-Python.ipynb @@ -20,36 +20,36 @@ "\n", "Quatre solveurs, un même problème NP-complet, des compromis différents. Ce notebook deplace le curseur de la serie *Search* : on ne presente plus un solveur a la fois, on les **fait courir ensemble** sur un banc commun (Easy / Medium / Hard) pour faire apparaitre ce que chaque algorithme optimise reellement.\n", "\n", - "Le fil rouge est le **denombrement du travail** : nombre d'appels recursifs, temps CPU, taux de reussite. On verra que la complexite asymptotique cache une realite pragmatique ou un *bon heuristique* (MRV) ou un *bon encodage* (Dancing Links) l'emporte sur la théorie pure.\n", + "Le fil rouge est le **denombrement du travail** : nombre d'appels recursifs, temps CPU, taux de reussite. On verra que la complexité asymptotique cache une realite pragmatique ou un *bon heuristique* (MRV) ou un *bon encodage* (Dancing Links) l'emporte sur la théorie pure.\n", "\n", "## Pourquoi ce notebook\n", "\n", "Les notebooks précédents de la serie *Search/Part3-Cas-pratiques* (App-1 N-Queens, App-2 Graph Coloring, App-3 Nurse Scheduling, App-4 Job Shop...) presentent chacun **une seule approche** sur **un seul problème**. Ce notebook inverse la perspective : un problème (Sudoku), **plusieurs solveurs** (backtracking, MRV, AC-3, DLX), un même banc de test.\n", "\n", - "Cette mise en regard est pedagogiquement plus riche qu'une suite monographique : elle fait apparaitre les **frontieres de viabilite** (quand MRV devient-il indispensable ? ou AC-3 paye-t-il son cout ? DLX garde-t-il son avantage sur les grilles très denses ?). Le lecteur peut lire la cellule de chaque solveur isolement, mais gagne beaucoup a voir les chiffres cotes a cotes en fin de notebook.\n", + "Cette mise en regard est pedagogiquement plus riche qu'une suite monographique : elle fait apparaitre les **frontieres de viabilite** (quand MRV devient-il indispensable ? ou AC-3 paye-t-il son coût ? DLX garde-t-il son avantage sur les grilles très denses ?). Le lecteur peut lire la cellule de chaque solveur isolement, mais gagne beaucoup a voir les chiffres cotes a cotes en fin de notebook.\n", "\n", "## Objectifs d'apprentissage\n", "\n", "A l'issue de ce notebook, vous serez capable de :\n", "\n", - "1. **Implementer** quatre solveurs Python de complexite croissante (naif, MRV, AC-3, Dancing Links)\n", + "1. **Implementer** quatre solveurs Python de complexité croissante (naïf, MRV, AC-3, Dancing Links)\n", "2. **Choisir** le solveur adapte a une difficulte donnee (règle pragmatique, pas théorique)\n", - "3. **Diagnostiquer** la complexite reelle d'un solveur via compteur d'appels + temps CPU\n", + "3. **Diagnostiquer** la complexité reelle d'un solveur via compteur d'appels + temps CPU\n", "4. **Construire** un banc de test reproductible (mêmes grilles, même budget, mêmes metriques)\n", "\n", "## Prong B — problème non trivial (anti-cas degenere, EPIC #3801)\n", "\n", - "Les trois grilles de test (Easy 36 indices, Medium 30, Hard 24) sont choisies pour que **les solveurs se distinguent**. Sur une grille facile (Easy), le backtracking simple termine en runtime *machine-dep* (de l'ordre de la milliseconde) et les quatre solveurs sont indiscernables — c'est le cas degenere que les règles SOTA-not-workaround nous demandent d'eviter. Le banc presente des **grilles ou l'ecart est mesurable**, ou MRV divise le nombre d'appels par un facteur *machine-dep*, ou AC-3 brille par la reduction du domaine, ou DLX garde son avantage constant grace a son encodage exact-cover.\n", + "Les trois grilles de test (Easy 36 indices, Medium 30, Hard 24) sont choisies pour que **les solveurs se distinguent**. Sur une grille facile (Easy), le backtracking simple termine en runtime *machine-dep* (de l'ordre de la milliseconde) et les quatre solveurs sont indiscernables — c'est le cas degenere que les règles SOTA-not-workaround nous demandent d'éviter. Le banc presente des **grilles ou l'ecart est mesurable**, ou MRV divise le nombre d'appels par un facteur *machine-dep*, ou AC-3 brille par la reduction du domaine, ou DLX garde son avantage constant grace a son encodage exact-cover.\n", "\n", "## Methodologie\n", "\n", "- Mêmes grilles pour les 4 solveurs (3 difficultes : Easy, Medium, Hard)\n", "- Mêmes metriques : temps CPU (runtime *machine-dep*), nombre d'appels recursifs (invariant structurel, **critere canonique de parite cross-langage Python↔C#** avec le notebook twin App-20b), succes (1/1)\n", - "- Budget temps : **60 s par (solveur x difficulte)** = **parametre de benchmark** deterministe, au-dela = TIMEOUT (compte comme echec)\n", + "- Budget temps : **60 s par (solveur x difficulte)** = **paramètre de benchmark** déterministe, au-dela = TIMEOUT (compte comme echec)\n", "- Ordre d'exécution : du plus simple au plus structure (Backtracking → MRV → AC-3 → DLX)\n", - "- Random seed fixe (`seed=42`) pour reproductibilite des grilles Medium/Hard aleatoires\n", + "- Random seed fixe (`seed=42`) pour reproductibilite des grilles Medium/Hard aléatoires\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : dans ce notebook, les **nombres d'appels recursifs** et le **statut succes** sont des **invariants structurels** (resultats solveur sur instance specifique, deterministes sur `seed=42` et les grilles pre-definies). En revanche, les **temps CPU** et les **ratios qualitatifs** (rapide, plus rapide, divise par 10) sont **machine-dep** (CPython, charge systeme, version Python, taille de l'instance) et **ne survivent pas** a une re-execution sur une autre machine. Le **critere de comparaison canonique** entre solveurs et entre langages (Python ici, C# via App-20b) reste le **nombre d'appels** (deterministe). Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note methodologique -- separation structurel / machine-dep** : dans ce notebook, les **nombres d'appels recursifs** et le **statut succes** sont des **invariants structurels** (résultats solveur sur instance spécifique, déterministes sur `seed=42` et les grilles pre-définies). En revanche, les **temps CPU** et les **ratios qualitatifs** (rapide, plus rapide, divise par 10) sont **machine-dep** (CPython, charge système, version Python, taille de l'instance) et **ne survivent pas** a une re-exécution sur une autre machine. Le **critere de comparaison canonique** entre solveurs et entre langages (Python ici, C# via App-20b) reste le **nombre d'appels** (déterministe). Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n", "## References\n", "\n", @@ -78,7 +78,7 @@ "\n", "Bibliotheques utilisees :\n", "- `time` (stdlib) — mesure CPU\n", - "- `random` (stdlib) — generation de grilles aleatoires reproductibles (seed=42)\n", + "- `random` (stdlib) — generation de grilles aléatoires reproductibles (seed=42)\n", "- `copy` (stdlib) — deep-copy pour AC-3 (on mute les domaines)\n", "- `typing` (stdlib) — annotations PEP 484\n", "\n", @@ -157,7 +157,7 @@ "\n", "Les grilles sont encodees comme `List[List[int]]` (0 = case vide). Source : grilles classiques du domaine public, format 9x9 standard.\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : les **3 difficultes** et le **budget 60 s** sont des parametres deterministes (invariants structurels). En revanche, l'ordre de grandeur temporel des solveurs (runtime *machine-dep*) depend du runtime (CPython, charge systeme, version Python) et n'est pas invariant. L'**invariant** pour comparer les solveurs reste le **nombre d'appels recursifs** (deterministe sur l'instance seedée).\n", + "> **Note methodologique -- separation structurel / machine-dep** : les **3 difficultes** et le **budget 60 s** sont des paramètres déterministes (invariants structurels). En revanche, l'ordre de grandeur temporel des solveurs (runtime *machine-dep*) depend du runtime (CPython, charge système, version Python) et n'est pas invariant. L'**invariant** pour comparer les solveurs reste le **nombre d'appels recursifs** (déterministe sur l'instance seedée).\n", "\n" ] }, @@ -262,9 +262,9 @@ "source": [ "## 3. Solveur 1 — Backtracking simple\n", "\n", - "Le plus naif des solveurs : on essaie les valeurs 1..9 dans l'ordre sur la première case vide, on recurse, on backtracke si conflit. Aucun heuristique, aucun filtrage.\n", + "Le plus naïf des solveurs : on essaie les valeurs 1..9 dans l'ordre sur la première case vide, on recurse, on backtracke si conflit. Aucun heuristique, aucun filtrage.\n", "\n", - "**Complexite théorique** : O(9^n) avec n = cases vides. En pratique, sur les grilles Hard (24 indices), c'est prohibitif (centaines de millions d'appels).\n", + "**Complexité théorique** : O(9^n) avec n = cases vides. En pratique, sur les grilles Hard (24 indices), c'est prohibitif (centaines de millions d'appels).\n", "\n", "**Ce solveur sert de baseline** : tout l'intérêt du notebook est de voir comment MRV, AC-3 et DLX s'ecartent de cette baseline sur les grilles difficiles.\n" ] @@ -381,7 +381,7 @@ "\n", "**Conditionnement** : la verification de validite est la même que pour le solveur 1 — MRV ne change pas la condition d'acceptation d'un coup, juste l'ordre d'exploration.\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : le **fait** que MRV reduit le nombre d'appels par rapport au backtracking naif est un **invariant structurel** (propriété algorithmique, valide sur les instances seedées). Le **facteur** de reduction exact (cite plus haut comme *machine-dep*) depend de la machine et de la version CPython. L'**invariant** pour comparer reste le **nombre d'appels** (sortie de la cellule benchmark ci-dessous, deterministe).\n", + "> **Note methodologique -- separation structurel / machine-dep** : le **fait** que MRV réduit le nombre d'appels par rapport au backtracking naïf est un **invariant structurel** (propriété algorithmique, valide sur les instances seedées). Le **facteur** de reduction exact (cite plus haut comme *machine-dep*) depend de la machine et de la version CPython. L'**invariant** pour comparer reste le **nombre d'appels** (sortie de la cellule benchmark ci-dessous, déterministe).\n", "\n" ] }, @@ -487,11 +487,11 @@ "\n", "AC-3 est un algorithme de **filtrage** qui restreint les domaines des variables avant la recherche : pour chaque paire de variables liees par une contrainte, on elimine les valeurs du domaine de l'une qui ne sont compatibles avec aucune valeur de l'autre. On repete jusqu'a stabilite (point fixe).\n", "\n", - "**Combine avec backtracking** : après AC-3, le domaine initial de chaque case est reduit. Le backtracking qui suit explore donc beaucoup moins de branches — MRV devient encore plus discriminant (les cases a 0 valeur sortent immediatement).\n", + "**Combine avec backtracking** : après AC-3, le domaine initial de chaque case est réduit. Le backtracking qui suit explore donc beaucoup moins de branches — MRV devient encore plus discriminant (les cases a 0 valeur sortent immediatement).\n", "\n", "**Contraintes Sudoku** : pour chaque case, le domaine est `{1..9}` ; on a environ 810 paires de cases liees (ligne/colonne/carre partagent une contrainte binaire « pas la même valeur »).\n", "\n", - "**Limite** : AC-3 est un **filtrage**, pas une resolution. Il peut ne rien conclure sur une grille très contrainte (toutes les cases ont encore plusieurs valeurs). Le backtracking reste necessaire.\n" + "**Limite** : AC-3 est un **filtrage**, pas une resolution. Il peut ne rien conclure sur une grille très contrainte (toutes les cases ont encore plusieurs valeurs). Le backtracking reste nécessaire.\n" ] }, { @@ -651,11 +651,11 @@ "\n", "**Dancing Links** (DLX) est l'implementation de l'**Algorithme X** de Knuth sous forme de listes doublement chainees circulaires. L'idee : encoder le Sudoku comme un problème d'**exact cover** (chaque case contient exactement un chiffre ; chaque ligne/colonne/carre 9 contient chaque chiffre 1..9 une fois), puis exploiter la structure de la matrice creuse pour backtracker avec un overhead minimal.\n", "\n", - "**Avantage algorithmique (invariant structurel)** : l'opération « couvrir une colonne » est O(1) grace aux pointeurs, et la « decouverte » (backtrack) aussi. Sur grilles très denses, DLX exploite cette structure exact-cover pour visiter **structurellement moins de nœuds** que les solveurs à propagation generique — c'est l'avantage **invariant** (propriete de l'encodage), independant de la machine.\n", + "**Avantage algorithmique (invariant structurel)** : l'opération « couvrir une colonne » est O(1) grace aux pointeurs, et la « decouverte » (backtrack) aussi. Sur grilles très denses, DLX exploite cette structure exact-cover pour visiter **structurellement moins de nœuds** que les solveurs à propagation generique — c'est l'avantage **invariant** (propriete de l'encodage), indépendant de la machine.\n", "\n", "**Encodage** : 324 colonnes (81 cases x 4 contraintes : case, ligne, colonne, carre) et 729 lignes candidates (81 cases x 9 valeurs). La matrice resultante est très creuse (4 ones par ligne).\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : l'avantage **structurel** de DLX (moins de nœuds visités grace a exact-cover + O(1)) est **invariant** (propriété algorithmique sur l'encodage). Le **runtime** lui-même (cite comme *le plus rapide* dans des observations empiriques) reste **machine-dep** (CPython overhead sur les structures de pointeurs, charge systeme) et **ne survit pas** a une re-execution. Le **critere canonique** pour comparer DLX aux autres solveurs reste le **nombre d'appels** (deterministe sur l'instance seedée).\n", + "> **Note methodologique -- separation structurel / machine-dep** : l'avantage **structurel** de DLX (moins de nœuds visités grace a exact-cover + O(1)) est **invariant** (propriété algorithmique sur l'encodage). Le **runtime** lui-même (cite comme *le plus rapide* dans des observations empiriques) reste **machine-dep** (CPython overhead sur les structures de pointeurs, charge système) et **ne survit pas** a une re-exécution. Le **critere canonique** pour comparer DLX aux autres solveurs reste le **nombre d'appels** (déterministe sur l'instance seedée).\n", "\n" ] }, @@ -870,9 +870,9 @@ "source": [ "## 7. Benchmark comparatif — les 4 solveurs sur 3 difficultes\n", "\n", - "Tableau final : pour chaque (solveur x difficulte), on reporte succes (invariant structurel), temps CPU (runtime *machine-dep*), nombre d'appels recursifs (**critere canonique**, invariant structurel). Le budget de **60 s par essai** est un **parametre de benchmark** deterministe.\n", + "Tableau final : pour chaque (solveur x difficulte), on reporte succes (invariant structurel), temps CPU (runtime *machine-dep*), nombre d'appels recursifs (**critere canonique**, invariant structurel). Le budget de **60 s par essai** est un **paramètre de benchmark** déterministe.\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : dans ce tableau, le **statut succes** et le **nombre d'appels** sont des **invariants structurels** (resultats solveur sur instance specifique, deterministes sur `seed=42` et les grilles pre-definies). Le **temps CPU** est **machine-dep** (CPython, charge systeme, version Python) et **ne survit pas** a une re-execution sur une autre machine. Le **critere canonique** pour comparer solveurs et langages (ici Python, twin C# via App-20b) reste le **nombre d'appels** (deterministe). Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", + "> **Note methodologique -- separation structurel / machine-dep** : dans ce tableau, le **statut succes** et le **nombre d'appels** sont des **invariants structurels** (résultats solveur sur instance spécifique, déterministes sur `seed=42` et les grilles pre-définies). Le **temps CPU** est **machine-dep** (CPython, charge système, version Python) et **ne survit pas** a une re-exécution sur une autre machine. Le **critere canonique** pour comparer solveurs et langages (ici Python, twin C# via App-20b) reste le **nombre d'appels** (déterministe). Pour observer vos propres timings, executez la cellule de benchmark ci-dessous.\n", "\n" ] }, @@ -981,11 +981,11 @@ "\n", "Lecture du tableau ci-dessus :\n", "\n", - "1. **Easy (36 indices)** : les 4 solveurs sont indiscernables en pratique (ms, < 1000 appels). C'est le cas degenere que les règles SOTA-not-workaround nous demandent d'eviter comme seul banc d'essai — c'est pour cela que le notebook presente aussi Medium et Hard.\n", + "1. **Easy (36 indices)** : les 4 solveurs sont indiscernables en pratique (ms, < 1000 appels). C'est le cas degenere que les règles SOTA-not-workaround nous demandent d'éviter comme seul banc d'essai — c'est pour cela que le notebook presente aussi Medium et Hard.\n", "\n", "2. **Medium (30 indices)** : MRV et AC-3 commencent a montrer leur intérêt (reduction du nombre d'appels). DLX reste comparable en temps malgre un overhead constant plus eleve (construction de la matrice 729 lignes).\n", "\n", - "3. **Hard (24 indices)** : ecarts significatifs. MRV divise typiquement les appels par 10 vs backtracking simple. AC-3 reduit drastiquement les domaines avant recherche. DLX garde un avantage grace au chainage O(1) de cover/uncover.\n", + "3. **Hard (24 indices)** : ecarts significatifs. MRV divise typiquement les appels par 10 vs backtracking simple. AC-3 réduit drastiquement les domaines avant recherche. DLX garde un avantage grace au chainage O(1) de cover/uncover.\n", "\n", "**Règle pragmatique** :\n", "- Grille avec beaucoup d'indices (Easy/Medium journaliere) : backtracking simple suffit, MRV est un confort.\n", @@ -1276,11 +1276,11 @@ "source": [ "## Exercice 1 — Propagation unitaire (unit propagation)\n", "\n", - "**Objectif** : etendre le solveur MRV avec **unit propagation** : après AC-3 (ou en plus de MRV), si une case a un domaine reduit a **une seule valeur** après filtrage, on l'assigne immediatement et on recommence le filtrage.\n", + "**Objectif** : etendre le solveur MRV avec **unit propagation** : après AC-3 (ou en plus de MRV), si une case a un domaine réduit a **une seule valeur** après filtrage, on l'assigne immediatement et on recommence le filtrage.\n", "\n", "**Indice** : après avoir assigne une case, rappeler `ac3(domains)` pour propager la reduction.\n", "\n", - "**Contexte pedagogique** : ce pas vers FC (Forward Checking) ou MAC (Maintaining Arc Consistency) est exactement ce que font les solveurs modernes type Choco/OR-Tools. Le rendre explicite est l'occasion de comprendre **pourquoi** un solveur industriel bat un MRV naif.\n" + "**Contexte pédagogique** : ce pas vers FC (Forward Checking) ou MAC (Maintaining Arc Consistency) est exactement ce que font les solveurs modernes type Choco/OR-Tools. Le rendre explicite est l'occasion de comprendre **pourquoi** un solveur industriel bat un MRV naïf.\n" ] }, { @@ -1438,7 +1438,7 @@ "- Retirer aleatoirement des cases, en verifiant a chaque retrait que la grille reste a **solution unique** (sinon remettre la case)\n", "- S'arreter quand on atteint le nombre d'indices cible\n", "\n", - "**Indice** : utiliser `copy.deepcopy` avant chaque tentative de retrait, et reutiliser un des solveurs ci-dessus pour verifier l'unicite (comparer les solutions sur les 4 solveurs — s'ils trouvent la même, c'est unique).\n" + "**Indice** : utiliser `copy.deepcopy` avant chaque tentative de retrait, et reutiliser un des solveurs ci-dessus pour vérifier l'unicite (comparer les solutions sur les 4 solveurs — s'ils trouvent la même, c'est unique).\n" ] }, { @@ -1521,16 +1521,16 @@ "source": [ "## Conclusion\n", "\n", - "Ce notebook a compare **quatre solveurs Python** sur un même banc de test (trois grilles de difficultes croissantes). Le résultat est clair : il n'y a pas de « bon » solveur dans l'absolu — il y a des compromis entre la simplicite d'implementation, le cout en memoire, et la rapidite sur les instances denses.\n", + "Ce notebook a compare **quatre solveurs Python** sur un même banc de test (trois grilles de difficultes croissantes). Le résultat est clair : il n'y a pas de « bon » solveur dans l'absolu — il y a des compromis entre la simplicite d'implementation, le coût en memoire, et la rapidite sur les instances denses.\n", "\n", - "**Le fil rouge du notebook** : passer d'un solveur naif (backtracking simple) a un solveur structure (DLX) montre que la richesse algorithmique d'un solveur de CSP ne reside pas dans la complexite asymptotique d'un seul algorithme, mais dans **l'interaction entre l'heuristique de sélection de variable** (MRV), **le filtrage des domaines** (AC-3), et **la structure de données** (DLX). Les solveurs industriels (Choco, OR-Tools, Gecode) combinent toutes ces techniques en un même moteur.\n", + "**Le fil rouge du notebook** : passer d'un solveur naïf (backtracking simple) a un solveur structure (DLX) montre que la richesse algorithmique d'un solveur de CSP ne reside pas dans la complexité asymptotique d'un seul algorithme, mais dans **l'interaction entre l'heuristique de sélection de variable** (MRV), **le filtrage des domaines** (AC-3), et **la structure de données** (DLX). Les solveurs industriels (Choco, OR-Tools, Gecode) combinent toutes ces techniques en un même moteur.\n", "\n", "**Tranche 2 (section 8)** : la confrontation au moteur de production OR-Tools CP-SAT confirme expérimentalement cette thèse — sur les mêmes grilles, sa propagation de contraintes globales fixe toutes les cases **sans aucune décision de recherche** (0 branche, même sur la grille Hard), là où le backtracking naïf déploie des centaines de milliers d'appels récursifs. Les deux tranches sont complémentaires : la première rend la mécanique visible, la seconde montre l'état de l'art une fois ces techniques industrialisées.\n", "\n", - "**Pour aller plus loin** : la serie *Search/Part3-Cas-pratiques* presente d'autres problemes (N-queens, Job Shop, Picross, Wordle) ou les mêmes compromis se posent avec des dominantes différentes.\n", + "**Pour aller plus loin** : la serie *Search/Part3-Cas-pratiques* presente d'autres problèmes (N-queens, Job Shop, Picross, Wordle) ou les mêmes compromis se posent avec des dominantes différentes.\n", "\n", "**References completes** :\n", - "- Russell & Norvig, *AIMA* 4e ed. chap. 6 (CSP) — la reference pedagogique pour backtracking, MRV, AC-3.\n", + "- Russell & Norvig, *AIMA* 4e ed. chap. 6 (CSP) — la reference pédagogique pour backtracking, MRV, AC-3.\n", "- Knuth, D. E. (2000). « Dancing Links ». *Millennial Perspectives in Computer Science*. — l'article fondateur de DLX.\n", "- Gent, I., et al. (2011). « Algorithms for the Constraint Satisfaction Problem ». — panorama des solveurs modernes.\n", "- Perron, L., & Furnon, V. — *Google OR-Tools CP-SAT* (documentation officielle), moteur de la tranche 2.\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20b-SudokuBenchmark-CSharp.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20b-SudokuBenchmark-CSharp.ipynb index 43b08a30d46..10c14ff514d 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20b-SudokuBenchmark-CSharp.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-20b-SudokuBenchmark-CSharp.ipynb @@ -16,8 +16,8 @@ "\n", "A la fin de ce notebook, vous saurez :\n", "\n", - "1. **Implementer from-scratch** quatre solveurs Sudoku d'complexite croissante : backtracking naif, backtracking + MRV, AC-3 + backtracking, Dancing Links (Knuth 2000).\n", - "2. **Mesurer** le cout exact (nombre d'appels recursifs, temps) de chaque approche sur un banc de trois grilles de difficulte croissante.\n", + "1. **Implementer from-scratch** quatre solveurs Sudoku d'complexité croissante : backtracking naïf, backtracking + MRV, AC-3 + backtracking, Dancing Links (Knuth 2000).\n", + "2. **Mesurer** le coût exact (nombre d'appels recursifs, temps) de chaque approche sur un banc de trois grilles de difficulte croissante.\n", "3. **Comparer** l'impact des heuristiques (MRV) et de la propagation de contraintes (AC-3) sur la taille de l'arbre de recherche.\n", "4. **Apprecier** pourquoi Dancing Links (formulation exact-cover) est asymptotiquement superieur au backtracking classical.\n", "\n", @@ -64,7 +64,7 @@ "***\n", "## 1. Banc de test -- trois grilles (Easy / Medium / Hard)\n", "\n", - "Trois grilles 9x9 representative des niveaux de difficulte (`0` = case vide). Elles sont **strictement identiques** au notebook Python, condition necessaire a la parite du nombre d'appels.\n" + "Trois grilles 9x9 representative des niveaux de difficulte (`0` = case vide). Elles sont **strictement identiques** au notebook Python, condition nécessaire a la parite du nombre d'appels.\n" ] }, { @@ -158,9 +158,9 @@ "metadata": {}, "source": [ "***\n", - "## 2. Solveur 1 -- backtracking naif\n", + "## 2. Solveur 1 -- backtracking naïf\n", "\n", - "Le solveur le plus simple : trouver la première case vide (ordre ligne-par-ligne, colonne-par-colonne), essayer les valeurs 1..9 dans l'ordre, verifier la validite (ligne + colonne + carre 3x3), et recurser. Aucune heuristique : l'arbre de recherche explose rapidement sur les grilles difficiles.\n" + "Le solveur le plus simple : trouver la première case vide (ordre ligne-par-ligne, colonne-par-colonne), essayer les valeurs 1..9 dans l'ordre, vérifier la validite (ligne + colonne + carre 3x3), et recurser. Aucune heuristique : l'arbre de recherche explose rapidement sur les grilles difficiles.\n" ] }, { @@ -238,7 +238,7 @@ "source": [ "### Solveur 2 -- backtracking + MRV (Minimum Remaining Values)\n", "\n", - "Le même backtracking, mais on choisit a chaque pas la case vide **avec le moins de valeurs possibles**. L'heuristique MRV reduit drastiquement le facteur de branchement : une case avec une seule valeur possible est remplie immediatement (propagation implicite), et les branches mortes sont coupees plus tot.\n" + "Le même backtracking, mais on choisit a chaque pas la case vide **avec le moins de valeurs possibles**. L'heuristique MRV réduit drastiquement le facteur de branchement : une case avec une seule valeur possible est remplie immediatement (propagation implicite), et les branches mortes sont coupees plus tot.\n" ] }, { @@ -713,16 +713,16 @@ "\n", "Les faits marquants (a confronter a la sortie ci-dessus) :\n", "\n", - "1. **Le backtracking naif explose sur les grilles difficiles** : le facteur de branchement 9 (essai de 1..9 dans l'ordre) sans aucune coupe produit un arbre gigantesque (879 418 appels sur Hard).\n", + "1. **Le backtracking naïf explose sur les grilles difficiles** : le facteur de branchement 9 (essai de 1..9 dans l'ordre) sans aucune coupe produit un arbre gigantesque (879 418 appels sur Hard).\n", "2. **MRV divise drastiquement le nombre d'appels** : en choisissant la case la plus contrainte, on remplit les singletons immediatement et on coupe les branches mortes très tot (Hard passe de 879 418 a 5 565 appels).\n", - "3. **AC-3 ajoute une propagation pre-recherche** : la consistance d'arc reduit les domaines avant le backtracking. Sur Easy/Medium le nombre d'appels est faible, mais sur Hard la propagation ne suffit pas a eviter l'explosion (981 113 appels).\n", - "4. **DLX est dans une autre categorie** : la formulation exact-cover + Dancing Links visite un nombre de nœuds independant des heuristiques de choix de variable, et chaque operation est O(1). Sur Hard, DLX resout en une fraction de milliseconde la ou le naif met des centaines.\n", + "3. **AC-3 ajoute une propagation pre-recherche** : la consistance d'arc réduit les domaines avant le backtracking. Sur Easy/Medium le nombre d'appels est faible, mais sur Hard la propagation ne suffit pas a éviter l'explosion (981 113 appels).\n", + "4. **DLX est dans une autre catégorie** : la formulation exact-cover + Dancing Links visite un nombre de nœuds indépendant des heuristiques de choix de variable, et chaque opération est O(1). Sur Hard, DLX resout en une fraction de milliseconde la ou le naïf met des centaines.\n", "\n", "### Parite Python / C# (critere = nombre d'appels recursifs)\n", "\n", - "Les trois solveurs déterministes (naif, MRV, AC-3) visitent **exactement le meme nombre de nœuds** en C# et en Python :\n", + "Les trois solveurs déterministes (naïf, MRV, AC-3) visitent **exactement le même nombre de nœuds** en C# et en Python :\n", "\n", - "| Grille | Naif | MRV | AC-3 |\n", + "| Grille | Naïf | MRV | AC-3 |\n", "|--------|------|-----|------|\n", "| Easy | 4209 | 52 | 82 |\n", "| Medium | 55 | 46 | 82 |\n", @@ -732,14 +732,14 @@ "\n", "### Ecart runtime : C# .NET vs CPython (machine-dep, documente honnetement)\n", "\n", - "Le **temps** wall-clock depend du runtime (JIT .NET vs CPython, charge systeme, version .NET, machine), et cet ecart a un effet visible sur le benchmark :\n", + "Le **temps** wall-clock depend du runtime (JIT .NET vs CPython, charge système, version .NET, machine), et cet ecart a un effet visible sur le benchmark :\n", "\n", - "- **Hard, AC-3** : le Python original **timeout** (runtime *machine-dep* ; `succes=False` a l'issue du budget 60 s, qui est un **parametre de benchmark** deterministe) apres 981 113 appels. Ce twin C# **termine sous le budget** (runtime *machine-dep*) avec le **meme nombre d'appels** (981 113). La difference de succes apparente (False cote Python, True cote C#) n'est **pas** un bug : elle reflete l'avantage du JIT .NET sur CPython pour les boucles tight. Le critere de parite (nombre d'appels) est respecte ; le temps, lui, est runtime-dependant.\n", - "- De meme, le naif sur Hard met runtime *machine-dep* en Python (parametre \"wall-clock\" specifie dans le notebook Python jumeau App-20) et runtime *machine-dep* en C#, facteur *machine-dep*, meme arbre de recherche.\n", + "- **Hard, AC-3** : le Python original **timeout** (runtime *machine-dep* ; `succes=False` a l'issue du budget 60 s, qui est un **paramètre de benchmark** déterministe) après 981 113 appels. Ce twin C# **termine sous le budget** (runtime *machine-dep*) avec le **même nombre d'appels** (981 113). La différence de succes apparente (False cote Python, True cote C#) n'est **pas** un bug : elle reflete l'avantage du JIT .NET sur CPython pour les boucles tight. Le critere de parite (nombre d'appels) est respecte ; le temps, lui, est runtime-dependant.\n", + "- De même, le naïf sur Hard met runtime *machine-dep* en Python (paramètre \"wall-clock\" specifie dans le notebook Python jumeau App-20) et runtime *machine-dep* en C#, facteur *machine-dep*, même arbre de recherche.\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : le **nombre d'appels recursifs** (table ci-dessus) est un **invariant structurel** (resultat solveur sur instance specifique, deterministe sur la grainee fixee SEED=42) -- c'est le **critere de parite** entre les deux langages. En revanche, le **temps wall-clock** (runtime C# et Python), le **timeout** eventuel, et le **ratio cross-runtime** sont **machine-dep** (JIT .NET vs CPython, charge systeme, version .NET, taille de l'instance) et **ne survivent pas** a une re-execution sur une autre machine. L'ordre de grandeur qualitatif (C# naif/baseline rapide vs C# naif Hard lent, C# DLX tres rapide) reste structurel, mais le ratio exact est lui aussi **machine-dep**. Pour observer vos propres timings, executez la cellule de benchmark ci-dessus (la cellule `RunByName` utilise `Stopwatch` pour mesurer le wall-clock).\n", + "> **Note methodologique -- separation structurel / machine-dep** : le **nombre d'appels recursifs** (table ci-dessus) est un **invariant structurel** (résultat solveur sur instance spécifique, déterministe sur la grainee fixee SEED=42) -- c'est le **critere de parite** entre les deux langages. En revanche, le **temps wall-clock** (runtime C# et Python), le **timeout** eventuel, et le **ratio cross-runtime** sont **machine-dep** (JIT .NET vs CPython, charge système, version .NET, taille de l'instance) et **ne survivent pas** a une re-exécution sur une autre machine. L'ordre de grandeur qualitatif (C# naïf/baseline rapide vs C# naïf Hard lent, C# DLX très rapide) reste structurel, mais le ratio exact est lui aussi **machine-dep**. Pour observer vos propres timings, executez la cellule de benchmark ci-dessus (la cellule `RunByName` utilise `Stopwatch` pour mesurer le wall-clock).\n", "\n", - "Le point pedagogique (l'explosion combinatoire du naif, le gain de MRV, la superieur asymptotique de DLX) est **identique** dans les deux langages ; seul le mur de temps (le budget parametrable de 60 s) est franchi ou non selon le runtime.\n", + "Le point pédagogique (l'explosion combinatoire du naïf, le gain de MRV, la superieur asymptotique de DLX) est **identique** dans les deux langages ; seul le mur de temps (le budget parametrable de 60 s) est franchi ou non selon le runtime.\n", "\n" ] }, @@ -967,7 +967,7 @@ "| `presolve=off` | 0 (Easy, Medium), quelques unités (Hard) | quelques unités sur Hard seulement | sans le présolve, la recherche SAT n'intervient quasiment pas : la propagation des 27 contraintes `AllDifferent` suffit déjà |\n", "\n", "- **L'héroïne, c'est la propagation** : le socle from-scratch montrait déjà que MRV coupait 879 418 appels à 5 565 et que DLX passait sous la milliseconde ; CP-SAT pousse la logique à son terme -- avec le présolve activé, **zéro branche, même sur la grille Hard**. Le travail est fait par les propagateurs : chaque `AddAllDifferent` embarque un filtrage par algorithme de flot (matching), bien plus fort que l'AC-3 du socle.\n", - "- **Branches CP-SAT ≠ appels récursifs du socle** : les compteurs des deux tranches ne se comparent pas un à un -- ils mesurent des machines de recherche différentes. Ce qui est comparable, c'est le contraste qualitatif : chaque étage (naif -> MRV -> DLX -> CP-SAT) est séparé d'un ordre de grandeur.\n", + "- **Branches CP-SAT ≠ appels récursifs du socle** : les compteurs des deux tranches ne se comparent pas un à un -- ils mesurent des machines de recherche différentes. Ce qui est comparable, c'est le contraste qualitatif : chaque étage (naïf -> MRV -> DLX -> CP-SAT) est séparé d'un ordre de grandeur.\n", "- **Déterminisme par construction** : `num_search_workers:1` + `random_seed:42` + version épinglée 9.15.6755 => les compteurs de cette table sont reproductibles à l'identique et **doivent concorder avec le twin Python** (même moteur C++ sous-jacent des deux côtés). C'est la parité *native-both* : lib contre lib.\n", "- **Ce que la boîte noire industrialise** : heuristiques de choix de variable/valeur calibrées sur des années de recherche, réduction de domaine par flot, clauses apprises, élimination de symétries. Le socle from-scratch reste indispensable pour comprendre *ce que* le moteur fait ; cette tranche montre *ce qu'un moteur de production fait de ces idées*.\n", "\n", @@ -1030,7 +1030,7 @@ "source": [ "### Exercice 2 -- Compteur de nœuds explores pour DLX\n", "\n", - "Le solveur DLX ci-dessus retourne `calls=0` (il n'instrumente pas le nombre de nœuds visitees). Ajoutez un compteur dans `DLXSolver.Search` (incrementer a chaque entree de `Search`) et retournz-le via `RunDLX`. Comparez ce compte aux `calls` du backtracking naif et de MRV sur la grille Hard : l'ecart quantifie l'avantage de la formulation exact-cover.\n" + "Le solveur DLX ci-dessus retourne `calls=0` (il n'instrumente pas le nombre de nœuds visitees). Ajoutez un compteur dans `DLXSolver.Search` (incrementer a chaque entree de `Search`) et retournz-le via `RunDLX`. Comparez ce compte aux `calls` du backtracking naïf et de MRV sur la grille Hard : l'ecart quantifie l'avantage de la formulation exact-cover.\n" ] }, { @@ -1068,7 +1068,7 @@ "source": [ "### Exercice 3 -- Generation de grilles de difficulte controlee\n", "\n", - "Ecrivez un générateur qui produit une grille de difficulte parametree : (1) resoudre une grille vide avec un solveur pour obtenir une solution complete, (2) retirer k cases au hasard tout en verifier (par re-solution) que la grille reste a solution unique. Le paramètre k contrôle la difficulte. Indice : utiliser `RunBacktracking` comme oracle d'unicite.\n" + "Ecrivez un générateur qui produit une grille de difficulte parametree : (1) résoudre une grille vide avec un solveur pour obtenir une solution complete, (2) retirer k cases au hasard tout en vérifier (par re-solution) que la grille reste a solution unique. Le paramètre k contrôle la difficulte. Indice : utiliser `RunBacktracking` comme oracle d'unicite.\n" ] }, { @@ -1116,32 +1116,32 @@ "\n", "Ce twin C# a reconstruit depuis zero les quatre solveurs Sudoku du notebook Python :\n", "\n", - "1. **Backtracking naif** -- baseline, explosion combinatoire ;\n", + "1. **Backtracking naïf** -- baseline, explosion combinatoire ;\n", "2. **Backtracking + MRV** -- heuristique de choix de variable, coupe massive ;\n", "3. **AC-3 + backtracking** -- propagation de consistance d'arc avant recherche ;\n", "4. **Dancing Links (Knuth 2000)** -- formulation exact-cover, asymptotiquement superieur ;\n", "5. **OR-Tools CP-SAT (Tranche 2, section 4)** -- moteur de production Google (Perron & Furnon), appelé des deux côtés de la parité : `Google.OrTools` 9.15.6755 en C# et `ortools` 9.15.6755 en Python.\n", "\n", - "La **Tranche 2 (section 4)** confronte le socle from-scratch au moteur de production et confirme expérimentalement la thèse du socle -- avec le présolve activé, CP-SAT résout les trois grilles en **zéro branche**, même sur la grille Hard : tout le travail est fait par la propagation (filtrage par flot des 27 contraintes `AllDifferent`), pas par la recherche. C'est l'aboutissement de la progression naif -> MRV -> AC-3 -> DLX : chaque étage délègue davantage au raisonnement sur les domaines et moins à l'exploration aveugle.\n", + "La **Tranche 2 (section 4)** confronte le socle from-scratch au moteur de production et confirme expérimentalement la thèse du socle -- avec le présolve activé, CP-SAT résout les trois grilles en **zéro branche**, même sur la grille Hard : tout le travail est fait par la propagation (filtrage par flot des 27 contraintes `AllDifferent`), pas par la recherche. C'est l'aboutissement de la progression naïf -> MRV -> AC-3 -> DLX : chaque étage délègue davantage au raisonnement sur les domaines et moins à l'exploration aveugle.\n", "\n", "### Parite Python / C#\n", "\n", "- Les **trois grilles** (Easy/Medium/Hard) sont strictement identiques ;\n", - "- Le **nombre d'appels recursifs** (naif, MRV, AC-3) concorde exactement entre les deux langages (tableau §4) : c'est le critere de parite (algorithme déterministe) ;\n", + "- Le **nombre d'appels recursifs** (naïf, MRV, AC-3) concorde exactement entre les deux langages (tableau §4) : c'est le critere de parite (algorithme déterministe) ;\n", "- **Tranche 2 (native-both)** : CP-SAT est appelé via le **même moteur** des deux côtés (NuGet `Google.OrTools` vs pip `ortools`, même version 9.15.6755, `num_search_workers:1`, `random_seed:42`) -- les invariants (statut, validité, branches, conflicts, propagations) concordent exactement entre les deux jumeaux ;\n", - "- Le **temps** wall-clock depend du runtime (C# .NET JIT vs CPython, charge systeme), runtime *machine-dep* cote Python vs runtime *machine-dep* cote C#, ce n'est pas un critere de parite ;\n", - "- **Ecart runtime documente** : sur Hard+AC-3, le Python original timeout (runtime *machine-dep*, budget parametrable 60 s) alors que ce twin C# termine (runtime *machine-dep*) avec le meme nombre d'appels (981 113). La difference de succes apparente est un effet purement runtime, pas un bug.\n", + "- Le **temps** wall-clock depend du runtime (C# .NET JIT vs CPython, charge système), runtime *machine-dep* cote Python vs runtime *machine-dep* cote C#, ce n'est pas un critere de parite ;\n", + "- **Ecart runtime documente** : sur Hard+AC-3, le Python original timeout (runtime *machine-dep*, budget parametrable 60 s) alors que ce twin C# termine (runtime *machine-dep*) avec le même nombre d'appels (981 113). La différence de succes apparente est un effet purement runtime, pas un bug.\n", "\n", - "> **Note methodologique -- separation structurel / machine-dep** : tous les **nombres d'appels** et les **grilles** (Easy/Medium/Hard) sont des **invariants structurels** (resultats solveur sur instance specifique, deterministes sur la grainee SEED=42). En revanche, tous les **temps wall-clock** et les **ratios cross-runtime** cites dans cette conclusion sont **machine-dep** (JIT .NET vs CPython, charge systeme, version .NET) et **ne survivent pas** a une re-execution sur une autre machine. Le critere de parite reste le **nombre d'appels** (deterministe), pas le temps (runtime-dependent). Les compteurs CP-SAT de la Tranche 2 (branches, conflicts, propagations) sont deterministes eux aussi -- mono-worker, graine fixée -- et constituent le critere de parité *native-both*.\n", + "> **Note methodologique -- separation structurel / machine-dep** : tous les **nombres d'appels** et les **grilles** (Easy/Medium/Hard) sont des **invariants structurels** (résultats solveur sur instance spécifique, déterministes sur la grainee SEED=42). En revanche, tous les **temps wall-clock** et les **ratios cross-runtime** cites dans cette conclusion sont **machine-dep** (JIT .NET vs CPython, charge système, version .NET) et **ne survivent pas** a une re-exécution sur une autre machine. Le critere de parite reste le **nombre d'appels** (déterministe), pas le temps (runtime-dependent). Les compteurs CP-SAT de la Tranche 2 (branches, conflicts, propagations) sont déterministes eux aussi -- mono-worker, graine fixée -- et constituent le critere de parité *native-both*.\n", "\n", "### Ponts inter-series\n", "\n", "- **Dancing Links / couverture exacte** : cf. la formalisation DLX dans la serie Search et l'algorithme X de Knuth (cf. App-11 Picross pour une autre application de DLX) ;\n", - "- **AC-3 / propagation de contraintes** : cf. [Partie 2 (CSP)](../Part2-CSP/README.md) pour la theorie de la consistance d'arc ;\n", + "- **AC-3 / propagation de contraintes** : cf. [Partie 2 (CSP)](../Part2-CSP/README.md) pour la théorie de la consistance d'arc ;\n", "- **CP-SAT / OR-Tools** : cf. la serie Sudoku (Sudoku-10 ORTools C#) pour une première prise en main du moteur, et la documentation Perron & Furnon, *CP-SAT in Google OR-Tools* ;\n", - "- **App-20 Python** : la version originale avec la stdlib Python donne les memes nombres d'appels.\n", + "- **App-20 Python** : la version originale avec la stdlib Python donne les mêmes nombres d'appels.\n", "\n", - "### Prochaines etapes\n", + "### Prochaines étapes\n", "\n", "- Implementer les exercices (propagation unitaire, instrumentation DLX, generation de grilles) ;\n", "- Comparer DLX au backtracking sur des grilles 16x16 ou 25x25 (ou l'ecart s'elargit) ;\n", diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling-CSharp.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling-CSharp.ipynb index 43e08c3b36f..67de733d946 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling-CSharp.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling-CSharp.ipynb @@ -14,21 +14,21 @@ "## Objectifs d'apprentissage\n", "\n", "A la fin de ce notebook, vous saurez :\n", - "1. **Modeliser** un problème d'emploi du temps universitaire comme un CSP\n", + "1. **Modéliser** un problème d'emploi du temps universitaire comme un CSP\n", "2. **Implementer** une heuristique gloutonne MRV (Minimum Remaining Values)\n", - "3. **Resoudre** optimalement les petites instances par branch-and-bound avec elagage\n", + "3. **Résoudre** optimalement les petites instances par branch-and-bound avec elagage\n", "4. **Distinguer** la recherche par affectation complete vs slot-par-slot\n", "5. **Analyser** la complementarite avec le solveur OR-Tools CP-SAT (jumeau Python)\n", "\n", - "### Prerequis\n", + "### Prérequis\n", "- .NET 9.0 + .NET Interactive\n", "- [CSP-3 : Advanced](../Part2-CSP/CSP-3-Advanced.ipynb)\n", "\n", - "### Duree estimee : 35 minutes\n", + "### Durée estimee : 35 minutes\n", "\n", "## 1. Contexte — le University Timetabling Problem\n", "\n", - "La **planification d'emplois du temps** est un problème classique d'optimisation sous contraintes. Une universite doit affecter chaque cours a un creneau horaire et une salle, en respectant des règles dures (capacite, equipement, non-chevauchement) et en optimisant des critères souples (trous, equilibre).\n", + "La **planification d'emplois du temps** est un problème classique d'optimisation sous contraintes. Une universite doit affecter chaque cours a un creneau horaire et une salle, en respectant des règles dures (capacité, equipement, non-chevauchement) et en optimisant des critères souples (trous, equilibre).\n", "\n", "### Pourquoi ce problème est-il difficile ?\n", "\n", @@ -42,12 +42,12 @@ "\n", "| Type | Description | Exemples | Violation |\n", "|------|-------------|----------|-----------|\n", - "| **Dur** | Doit etre satisfaite | Capacite salle, equipement, non-chevauchement | Solution invalide |\n", + "| **Dur** | Doit etre satisfaite | Capacité salle, equipement, non-chevauchement | Solution invalide |\n", "| **Souple** | Souhaitable | Minimiser trous enseignants, equilibrer jours | Solution mediocre |\n", "\n", "### Le twin Python (App-5-Timetabling.ipynb)\n", "\n", - "Ce notebook jumeau C# est un **twin from-scratch** (BCL .NET 9, 0 NuGet) qui transpose les algorithmes en C#. Le jumeau Python utilise **OR-Tools CP-SAT** (le vrai solveur SOTA). Voir la section 6 sur la complementarite pedagogique.\n", + "Ce notebook jumeau C# est un **twin from-scratch** (BCL .NET 9, 0 NuGet) qui transpose les algorithmes en C#. Le jumeau Python utilise **OR-Tools CP-SAT** (le vrai solveur SOTA). Voir la section 6 sur la complementarite pédagogique.\n", "\n", "***\n", "\n", @@ -98,7 +98,7 @@ "\n", "Chaque cours a : nom, nombre d'etudiants, enseignant responsable, equipement requis.\n", "\n", - "Chaque salle a : capacite maximale, equipement disponible.\n", + "Chaque salle a : capacité maximale, equipement disponible.\n", "\n", "L'objectif : affecter chaque cours a un **(salle, creneau)** tel que les contraintes dures soient satisfaites et les souples minimisees." ] @@ -202,12 +202,12 @@ "source": [ "### Interpretation : la combinatoire revelee\n", "\n", - "**Points cles a observer** :\n", + "**Points clés a observer** :\n", "\n", "| Aspect | Observation | Impact |\n", "|--------|-------------|--------|\n", - "| Capacite Amphi_A (120) | Seule salle pour Algo (90) et IA (100) | Contrainte dure sur l'amphi |\n", - "| Equipement \"labo\" | Reseaux, Securite, Web le necessitent | Force Labo_C ou Labo_D |\n", + "| Capacité Amphi_A (120) | Seule salle pour Algo (90) et IA (100) | Contrainte dure sur l'amphi |\n", + "| Equipement \"labo\" | Réseaux, Securite, Web le necessitent | Force Labo_C ou Labo_D |\n", "| Dupont enseigne 2 cours | Algo + Systèmes | Pas de chevauchement temporel |\n", "| Martin enseigne 2 cours | Probas + IA | Idem |\n", "\n", @@ -381,7 +381,7 @@ "source": [ "### Interpretation : MRV revele par la structure\n", "\n", - "On observe que **Reseaux, Securite, Web** (cours \"labo\") ont moins de salles compatibles : 2 au lieu de 3-4. Ces cours sont les plus contraints — l'heuristique MRV (Minimum Remaining Values) du notebook suivant les placera en premier." + "On observe que **Réseaux, Securite, Web** (cours \"labo\") ont moins de salles compatibles : 2 au lieu de 3-4. Ces cours sont les plus contraints — l'heuristique MRV (Minimum Remaining Values) du notebook suivant les placera en premier." ] }, { @@ -574,7 +574,7 @@ "source": [ "### Interpretation : glouton MRV\n", "\n", - "**Sortie observee** : le glouton place tous les cours (l'instance n'est pas trop contrainte), mais la qualite est perfectible :\n", + "**Sortie observee** : le glouton place tous les cours (l'instance n'est pas trop contrainte), mais la qualité est perfectible :\n", "\n", "- **Placement rapide** : quelques ms, pas de backtracking\n", "- **Concentration temporelle** : beaucoup de cours les premiers jours (Lundi-Mardi), desequilibre\n", @@ -585,7 +585,7 @@ "2. Aucune optimisation des contraintes souples\n", "3. Pas de backtracking : sur des instances plus contraintes, le glouton echouerait\n", "\n", - "> **Conclusion** : pour l'optimalite, il faut un algorithme de recherche avec backtracking et elagage." + "> **Conclusion** : pour l'optimalité, il faut un algorithme de recherche avec backtracking et elagage." ] }, { @@ -605,7 +605,7 @@ "\n", "1. **Enumere** les affectations (cours, salle, creneau) une par une par ordre MRV\n", "2. **Elague** quand une contrainte dure est violee\n", - "3. **Compte** les solutions completes pour valider l'optimalite (toutes satisfont les dures → on prend la 1ere trouvee comme proxy optimal)\n", + "3. **Compte** les solutions completes pour valider l'optimalité (toutes satisfont les dures → on prend la 1ere trouvee comme proxy optimal)\n", "\n", "### Borne théorique\n", "\n", @@ -807,7 +807,7 @@ "\n", "**Comparaison directe** :\n", "\n", - "| Approche | Solutions | Temps | Noeuds | Qualite |\n", + "| Approche | Solutions | Temps | Noeuds | Qualité |\n", "|----------|-----------|-------|--------|---------|\n", "| Glouton MRV | 1 (premier trouve) | ~ms | 1 (greedy) | Bonne mais non optimale |\n", "| B&B complet | N (toutes) | 100ms-2s selon N | Variable | Optimale (contraintes dures) |\n", @@ -826,7 +826,7 @@ "\n", "## 6. Visualisation ASCII (Prong B assumé)\n", "\n", - "Pour visualiser le résultat sans bibliotheque graphique (matplotlib non disponible en .NET Interactive par defaut), nous utilisons une **grille ASCII**. Le twin Python utilise matplotlib ; ici, le C# assume une representation textuelle pedagogiquement equivalente." + "Pour visualiser le résultat sans bibliotheque graphique (matplotlib non disponible en .NET Interactive par defaut), nous utilisons une **grille ASCII**. Le twin Python utilise matplotlib ; ici, le C# assume une représentation textuelle pedagogiquement equivalente." ] }, { @@ -1174,7 +1174,7 @@ "- Le **glouton** concentre les cours en debut de semaine (ordre MRV + premier creneau libre)\n", "- Le **B&B** distribue mieux les cours sur la semaine grace a l'enumeration\n", "\n", - "C'est exactement la **différence pedagogique** que Prong B cherche a exhiber : CP-SAT fait ce que B&B fait, mais avec propagation de contraintes + branchements adaptatifs + recherche parallele. Le twin Python le montre avec matplotlib + OR-Tools ; le twin C# le montre avec ASCII + B&B from-scratch." + "C'est exactement la **différence pédagogique** que Prong B cherche a exhiber : CP-SAT fait ce que B&B fait, mais avec propagation de contraintes + branchements adaptatifs + recherche parallele. Le twin Python le montre avec matplotlib + OR-Tools ; le twin C# le montre avec ASCII + B&B from-scratch." ] }, { @@ -1395,7 +1395,7 @@ "source": [ "### Interprétation : parité lib-vs-lib, CP-SAT optimise là où le from-scratch satisfait\n", "\n", - "**Validation.** CP-SAT retrouve une affectation réalisable **et** retourne le statut `Optimal` en ~50 ms. Toutes les contraintes dures sont respectées : les 4 cours exigeant l'Amphi_A (Algo, Probas, BDD, IA — capacité 100/90/80/75, seule salle ≥120) occupent 4 créneaux distincts ; aucun enseignant n'a deux cours au même créneau (Dupont : Algo/Systemes, Martin : Probas/IA, Bernard : Reseaux/Securite, Leroy : BDD/Web). C'est la preuve que le moteur SOTA confirme la sémantique « emploi du temps » du from-scratch.\n", + "**Validation.** CP-SAT retrouve une affectation réalisable **et** retourne le statut `Optimal` en ~50 ms. Toutes les contraintes dures sont respectées : les 4 cours exigeant l'Amphi_A (Algo, Probas, BDD, IA — capacité 100/90/80/75, seule salle ≥120) occupent 4 créneaux distincts ; aucun enseignant n'a deux cours au même créneau (Dupont : Algo/Systèmes, Martin : Probas/IA, Bernard : Réseaux/Securite, Leroy : BDD/Web). C'est la preuve que le moteur SOTA confirme la sémantique « emploi du temps » du from-scratch.\n", "\n", "**Prong-B — la discrimination (pourquoi CP-SAT compte).** Le glouton MRV et le Branch-and-Bound §3 trouvent des affectations **réalisables** (contraintes dures), mais **n'optimisent aucun objectif souple** : le glouton compacte les 8 cours sur Lundi, plaçant **2 cours en après-midi** (BDD 14h, IA 16h). **CP-SAT, lui, minimise** la pénalité d'après-midi et prouve l'**optimal à 0** : il répartit les cours sur deux matinées pour qu'aucun ne soit en après-midi. C'est exactement la différence entre *satisfaire les contraintes* (from-scratch) et *optimiser une préférence* (solveur exact) — le cœur pédagogique du timetabling.\n", "\n", @@ -1603,16 +1603,16 @@ "\n", "### Ce qu'on a vu\n", "\n", - "1. **Modelisation** d'un problème d'emploi du temps comme un CSP (variables = cours, domaine = (salle, creneau), contraintes dures = capacite/equipement/non-chevauchement)\n", + "1. **Modélisation** d'un problème d'emploi du temps comme un CSP (variables = cours, domaine = (salle, creneau), contraintes dures = capacité/equipement/non-chevauchement)\n", "2. **Glouton MRV** : rapide, sous-optimal, pas de backtracking\n", "3. **Branch-and-Bound** : optimal pour petites instances, enumeration avec elagage par contrainte dure\n", - "4. **Visualisation ASCII** : alternative pedagogique au matplotlib Python\n", + "4. **Visualisation ASCII** : alternative pédagogique au matplotlib Python\n", "\n", "### Complementarite avec le twin Python (#3801 Prong B)\n", "\n", "Ce notebook jumeau C# est un **twin from-scratch** (BCL .NET 9, 0 NuGet) qui transpose les algorithmes en C#. Le **vrai outil SOTA** pour ce problème est **OR-Tools CP-SAT** (propagation de contraintes + recherche arborescente + optimisation lineaire) — c'est exactement ce qu'invoque le twin Python [App-5-Timetabling.ipynb](App-5-Timetabling.ipynb).\n", "\n", - "**Pourquoi from-scratch ici, alors** : pour **exhiber la mecanique** que CP-SAT encapsule (MRV, backtracking, elagage par incompatibilite, propagation de bornes). C'est la **valeur pedagogique de Prong B** : **separer pour voir** ce que le solveur boite-noire cache.\n", + "**Pourquoi from-scratch ici, alors** : pour **exhiber la mecanique** que CP-SAT encapsule (MRV, backtracking, elagage par incompatibilite, propagation de bornes). C'est la **valeur pédagogique de Prong B** : **separer pour voir** ce que le solveur boite-noire cache.\n", "\n", "Le notebook assume cette posture dans la cellule d'introduction (verdict RECOVERABLE-MACHINE Prong-B ecrit). Pas de contournement paresseux : si on voulait la solution SOTA, on appellerait `Google.OrTools` NuGet (parfaitement installable). On **choisit** le from-scratch avec justification ecrite (Prong B), pas par defaut.\n", "\n", @@ -1643,4 +1643,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling.ipynb index 3466f9d8ced..8d01acd8d4c 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-5-Timetabling.ipynb @@ -49,17 +49,17 @@ "## Objectifs d'apprentissage\n", "\n", "A la fin de ce notebook, vous saurez :\n", - "1. **Modeliser** un problème d'emploi du temps universitaire comme un CSP\n", + "1. **Modéliser** un problème d'emploi du temps universitaire comme un CSP\n", "2. **Distinguer** contraintes dures et contraintes souples\n", "3. **Comparer** une approche heuristique gloutonne avec un solveur CP-SAT\n", - "4. **Decouvrir** la modelisation declarative MiniZinc\n", - "5. **Visualiser** et analyser la qualite d'un emploi du temps\n", + "4. **Decouvrir** la modélisation declarative MiniZinc\n", + "5. **Visualiser** et analyser la qualité d'un emploi du temps\n", "\n", - "### Prerequis\n", + "### Prérequis\n", "- Python 3.10+, numpy, matplotlib, ortools\n", "- [CSP-3 : Advanced](../Part2-CSP/CSP-3-Advanced.ipynb)\n", "\n", - "### Duree estimee : 50 minutes" + "### Durée estimee : 50 minutes" ] }, { @@ -94,8 +94,8 @@ "\n", "| Type | Description | Exemples | Violation |\n", "|------|-------------|----------|----------|\n", - "| **Contrainte dure** | Doit etre satisfaite (sinon pas de solution) | Pas de chevauchement de salle, capacite suffisante | Solution invalide |\n", - "| **Contrainte souple** | Souhaitable mais non obligatoire | Minimiser les trous, préférences enseignants | Solution de moindre qualite |\n", + "| **Contrainte dure** | Doit etre satisfaite (sinon pas de solution) | Pas de chevauchement de salle, capacité suffisante | Solution invalide |\n", + "| **Contrainte souple** | Souhaitable mais non obligatoire | Minimiser les trous, préférences enseignants | Solution de moindre qualité |\n", "\n", "En pratique, on cherche une solution qui satisfait **toutes** les contraintes dures et **minimise** les violations de contraintes souples.\n", "\n", @@ -104,7 +104,7 @@ "| Élément | Rôle | Exemple |\n", "|---------|------|--------|\n", "| **Cours** | Activites a planifier | Algorithmique, Probabilites... |\n", - "| **Salles** | Lieux d'enseignement (capacite, equipements) | Amphi A (120 places, video-projecteur) |\n", + "| **Salles** | Lieux d'enseignement (capacité, equipements) | Amphi A (120 places, video-projecteur) |\n", "| **Creneaux** | Plages horaires (jour + heure) | Lundi 8h-10h, Mardi 14h-16h |\n", "| **Enseignants** | Personnes affectees aux cours | Prof. Dupont (Algo + Systèmes) |\n", "\n", @@ -196,7 +196,7 @@ "- les equipements requis (ex : ordinateurs, labo)\n", "\n", "Chaque salle est decrite par :\n", - "- sa capacite maximale\n", + "- sa capacité maximale\n", "- les equipements disponibles" ] }, @@ -343,18 +343,18 @@ "\n", "**Sortie obtenue** : la cellule affiche le récapitulatif de l'instance — `Cours : 8`, `Salles : 4`, `Creneaux : 20 (5 jours x 4 creneaux)`, `Enseignants : 4` — puis calcule l'espace brut `(4 x 20)^8 = 1.68e+15`, qui matérialise l'explosion combinatoire évoquée en introduction. La seconde table liste les 4 salles (`Amphi_A` 120 places, `Salle_B` 60, `Labo_C` 40, `Labo_D` 60) : seules `Labo_C` et `Labo_D` disposent de l'équipement « labo ».\n", "\n", - "**Points cles a observer** :\n", + "**Points clés a observer** :\n", "\n", "| Aspect | Observation | Consequence |\n", "|--------|-------------|-------------|\n", - "| Capacite Amphi_A (120) | Seule salle pour Algo (90) et IA (100) | Conflit pour l'amphi |\n", - "| Equipement \"labo\" | Reseaux, Securite, Web le necessitent | Labo_C ou Labo_D |\n", + "| Capacité Amphi_A (120) | Seule salle pour Algo (90) et IA (100) | Conflit pour l'amphi |\n", + "| Equipement \"labo\" | Réseaux, Securite, Web le necessitent | Labo_C ou Labo_D |\n", "| Dupont enseigne 2 cours | Algo + Systèmes | Pas au même creneau |\n", "| Martin enseigne 2 cours | Probas + IA | Idem |\n", "\n", "Ces observations font emerger les premières contraintes :\n", "1. Les cours a gros effectif (Algo, IA) **doivent** aller dans Amphi_A\n", - "2. Les cours \"labo\" (Reseaux, Securite, Web) **doivent** aller dans Labo_C ou Labo_D (Reseaux et Web uniquement dans Labo_D)\n", + "2. Les cours \"labo\" (Réseaux, Securite, Web) **doivent** aller dans Labo_C ou Labo_D (Réseaux et Web uniquement dans Labo_D)\n", "3. Dupont et Martin ont chacun 2 cours : pas de chevauchement possible" ] }, @@ -688,9 +688,9 @@ "\n", "1. **Trier** les cours par degré de contrainte decroissant (les plus contraints d'abord)\n", "2. **Pour chaque cours**, parcourir les creneaux et salles dans l'ordre :\n", - " - Verifier que la salle est compatible (capacite, equipement)\n", - " - Verifier qu'il n'y a pas de conflit de salle (même creneau)\n", - " - Verifier qu'il n'y a pas de conflit d'enseignant (même creneau)\n", + " - Vérifier que la salle est compatible (capacité, equipement)\n", + " - Vérifier qu'il n'y a pas de conflit de salle (même creneau)\n", + " - Vérifier qu'il n'y a pas de conflit d'enseignant (même creneau)\n", "3. **Affecter** au premier creneau+salle valide trouve\n", "\n", "L'idee du tri par contrainte (\"fail-first\") est la même que l'heuristique MRV vue dans les fondations CSP.\n", @@ -921,7 +921,7 @@ "|--------|-------------|----------|\n", "| Placement rapide | Quelques millisecondes | Pas de problème |\n", "| Concentration le lundi | Tous les premiers creneaux sont le lundi | Desequilibre des jours |\n", - "| Pas d'optimisation | Trous possibles pour les enseignants | Qualite mediocre |\n", + "| Pas d'optimisation | Trous possibles pour les enseignants | Qualité mediocre |\n", "\n", "On lit aussi le biais d'ordre dans les affectations : les cours les plus contraints (une seule salle compatible) sont placés en priorité, et le parcours des créneaux commence au lundi 8h-10h — d'où la concentration `[8, 0, 0, 0, 0]`.\n", "\n", @@ -930,7 +930,7 @@ "2. Aucune optimisation des contraintes souples (trous, equilibre)\n", "3. Sur des instances plus contraintes, le glouton echouerait car il ne revient pas en arriere\n", "\n", - "> **Conclusion** : pour obtenir une solution de qualite, il faut un solveur capable d'explorer l'espace de recherche et d'optimiser les critères souples." + "> **Conclusion** : pour obtenir une solution de qualité, il faut un solveur capable d'explorer l'espace de recherche et d'optimiser les critères souples." ] }, { @@ -953,7 +953,7 @@ "\n", "OR-Tools de Google fournit le solveur **CP-SAT** (Constraint Programming - Satisfiability), un des solveurs de contraintes les plus performants disponibles.\n", "\n", - "### Modelisation\n", + "### Modélisation\n", "\n", "Pour chaque cours $c$ :\n", "- **Variable** `course_slot[c]` $\\in \\{0, 1, \\ldots, 19\\}$ : creneau horaire\n", @@ -963,7 +963,7 @@ "\n", "| Contrainte | Formulation | Raison |\n", "|-----------|-------------|--------|\n", - "| Capacite de la salle | Si `course_room[c] = r`, alors `capacity[r] >= students[c]` | Securite |\n", + "| Capacité de la salle | Si `course_room[c] = r`, alors `capacity[r] >= students[c]` | Securite |\n", "| Equipement compatible | Si `course_room[c] = r`, equipement requis disponible | Fonctionnel |\n", "| Pas de double reservation salle | Si `course_room[c1] == course_room[c2]`, alors `course_slot[c1] != course_slot[c2]` | Physique |\n", "| Pas de double reservation enseignant | Si `teacher[c1] == teacher[c2]`, alors `course_slot[c1] != course_slot[c2]` | Humain |\n", @@ -1350,10 +1350,10 @@ "| Equilibre des jours | Mediocre | Bien meilleur | Grace a l'objectif |\n", "| Trous enseignants | Non minimises | Minimises | Grace aux penalites |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. CP-SAT **garantit** de trouver une solution si elle existe (completude)\n", "2. Les contraintes souples sont modelisees comme un **objectif a minimiser**\n", - "3. Le modèle separe clairement la structure (contraintes dures) de la qualite (objectif)\n", + "3. Le modèle separe clairement la structure (contraintes dures) de la qualité (objectif)\n", "4. Le temps de resolution reste faible grace aux techniques de propagation et d'elagage internes au solveur\n", "\n", "Côté coûts, honnêtement : les temps imprimés (`0.28 ms` glouton, `41.3 ms` CP-SAT) sont machine-dépendants et non moyennés ; la grandeur qui fait foi est la qualité de la solution — objectif `0.0`, `0` trou, `100%` de cours le matin.\n", @@ -1521,12 +1521,12 @@ "| Critere | Glouton | CP-SAT | Gagnant |\n", "|---------|---------|--------|--------|\n", "| Rapidite | Quasi-instantane | Quelques ms | Glouton (leger) |\n", - "| Optimalite | Non garantie | Optimale (ou prouvee proche) | CP-SAT |\n", + "| Optimalité | Non garantie | Optimale (ou prouvee proche) | CP-SAT |\n", "| Completude | Non (peut echouer) | Oui (trouve une solution si possible) | CP-SAT |\n", - "| Facilite de modelisation | Simple (code iteratif) | Plus complexe (variables, contraintes) | Glouton |\n", + "| Facilite de modélisation | Simple (code iteratif) | Plus complexe (variables, contraintes) | Glouton |\n", "| Flexibilite | Difficile a adapter | Ajout de contraintes facile | CP-SAT |\n", "\n", - "**Points cles** :\n", + "**Points clés** :\n", "1. Le glouton est utile comme **baseline** ou pour obtenir une solution initiale rapide\n", "2. CP-SAT excelle des que l'on a des **contraintes souples** a optimiser\n", "3. Sur des instances plus grandes (50+ cours), le glouton echouerait tandis que CP-SAT resterait performant\n", @@ -1552,13 +1552,13 @@ "\n", "## 5. Introduction a MiniZinc (optionnel) (~10 min)\n", "\n", - "**MiniZinc** est un langage de modelisation **declaratif** pour les problemes de contraintes. Contrairement a CP-SAT ou l'on construit le modèle en Python (approche imperative), en MiniZinc on **declare** les variables, domaines et contraintes dans une syntaxe proche des mathematiques.\n", + "**MiniZinc** est un langage de modélisation **declaratif** pour les problèmes de contraintes. Contrairement a CP-SAT ou l'on construit le modèle en Python (approche imperative), en MiniZinc on **declare** les variables, domaines et contraintes dans une syntaxe proche des mathematiques.\n", "\n", "### Approche imperative vs declarative\n", "\n", "| Aspect | Imperatif (CP-SAT) | Declaratif (MiniZinc) |\n", "|--------|--------------------|-----------------------|\n", - "| Style | \"Comment resoudre\" | \"Quoi resoudre\" |\n", + "| Style | \"Comment résoudre\" | \"Quoi résoudre\" |\n", "| Syntaxe | API Python (model.add, model.new_int_var) | Langage dedie (var, constraint, solve) |\n", "| Solveur | CP-SAT integre | Choix du solveur (Gecode, Chuffed, CP-SAT...) |\n", "| Lisibilite | Code Python standard | Proche des specifications mathematiques |\n", @@ -1763,7 +1763,7 @@ "\n", "Decomposons la syntaxe MiniZinc :\n", "\n", - "| Élément MiniZinc | Equivalent Python/CP-SAT | Rôle |\n", + "| Élément MiniZinc | Équivalent Python/CP-SAT | Rôle |\n", "|-----------------|-------------------------|------|\n", "| `int: num_courses = 8` | `num_courses = 8` | Paramètre |\n", "| `array[1..n] of int: data` | `data = [...]` | Données |\n", @@ -2160,10 +2160,10 @@ "| Amphi_A | 120 | Algo, Probas, BDD, IA | 4 cours (20 %) | Seule salle pour les gros effectifs |\n", "| Salle_B | 60 | Systèmes | 1 cours (5 %) | Usage modéré |\n", "| Labo_C | 40 | Securite | 1 cours (5 %) | 40 étudiants, à la limite de la capacité |\n", - "| Labo_D | 60 | Reseaux, Web | 2 cours (10 %) | Seul labo compatible pour Reseaux et Web |\n", + "| Labo_D | 60 | Réseaux, Web | 2 cours (10 %) | Seul labo compatible pour Réseaux et Web |\n", "\n", - "**Points cles** :\n", - "1. Les contraintes d'equipement créent un **goulot d'etranglement** sur Labo_D (Reseaux et Web ne peuvent aller qu'a Labo_D, 2 cours pour 1 salle)\n", + "**Points clés** :\n", + "1. Les contraintes d'equipement créent un **goulot d'etranglement** sur Labo_D (Réseaux et Web ne peuvent aller qu'a Labo_D, 2 cours pour 1 salle)\n", "2. Amphi_A est sous-utilise en proportion mais indispensable pour les gros effectifs\n", "3. L'equilibre des jours depend directement de l'objectif d'optimisation\n", "\n", @@ -2725,14 +2725,14 @@ "\n", "| Approche | Principe | Forces | Faiblesses |\n", "|----------|----------|--------|------------|\n", - "| **Heuristique gloutonne** | Tri par contrainte + premier disponible | Rapide, simple a implementer | Pas d'optimalite, peut echouer |\n", - "| **CP-SAT (OR-Tools)** | Variables + contraintes + objectif | Complet, optimal, flexible | Modelisation plus complexe |\n", - "| **MiniZinc** | Modelisation declarative | Concis, lisible, multi-solveurs | Necessite installation externe |\n", + "| **Heuristique gloutonne** | Tri par contrainte + premier disponible | Rapide, simple a implementer | Pas d'optimalité, peut echouer |\n", + "| **CP-SAT (OR-Tools)** | Variables + contraintes + objectif | Complet, optimal, flexible | Modélisation plus complexe |\n", + "| **MiniZinc** | Modélisation declarative | Concis, lisible, multi-solveurs | Necessite installation externe |\n", "\n", - "### Lecons cles\n", + "### Lecons clés\n", "\n", - "1. **Separation dur/souple** : les contraintes dures definissent la faisabilite, les souples la qualite\n", - "2. **Modelisation > algorithme** : bien modeliser le problème est souvent plus important que le choix de l'algorithme\n", + "1. **Separation dur/souple** : les contraintes dures definissent la faisabilite, les souples la qualité\n", + "2. **Modélisation > algorithme** : bien modéliser le problème est souvent plus important que le choix de l'algorithme\n", "3. **Solveurs industriels** : CP-SAT peut traiter des instances avec des centaines de cours en quelques secondes\n", "4. **Declaratif vs imperatif** : MiniZinc permet de prototyper rapidement, CP-SAT s'integre mieux dans une application\n", "\n", @@ -2749,7 +2749,7 @@ "\n", "- [App-3 NurseScheduling](App-3-NurseScheduling.ipynb) : planification similaire dans le domaine medical\n", "- [App-4 JobShopScheduling](App-4-JobShopScheduling.ipynb) : ordonnancement avec precedences\n", - "- [App-8 MiniZinc](App-8-MiniZinc.ipynb) : modelisation declarative approfondie\n", + "- [App-8 MiniZinc](App-8-MiniZinc.ipynb) : modélisation declarative approfondie\n", "\n", "### References\n", "\n", diff --git a/scripts/notebook_tools/detect_accent_stripping.py b/scripts/notebook_tools/detect_accent_stripping.py index 9f39942bf09..ac97389d03a 100644 --- a/scripts/notebook_tools/detect_accent_stripping.py +++ b/scripts/notebook_tools/detect_accent_stripping.py @@ -347,6 +347,18 @@ "essayee": "essayée", "specialites": "spécialités", "legerete": "légèreté", + # #21277, troisieme fournee : forme relevee par l'audit visuel du site + # deploye (EPIC #10921, criterion 5) -- le titre et les intertitres de + # section "### Prerequis" sortaient sans accent sur le site public. + # MEME critere que ci-dessus, applique forme par forme sur le depot entier : + # (a) la graphie desaccentuee n'est PAS un mot francais valide + # ("prerequis" n'existe pas sans accent) -- pas d'homographe ; + # (b) aucun usage en prose anglaise ni dans un carnet jumeau `_en` : + # mesure sur `MyIA.AI.Notebooks/**` = 487 occurrences reparties sur + # 436 carnets FR, **0** dans un carnet `_en` ; + # (c) la forme accentuee est unique ("prerequis" est invariable, + # nom/adjectif ; pas d'hesitation participe/present). + "prerequis": "prérequis", } From 1251b936efbe6473d310ef46648609af8ee4befa Mon Sep 17 00:00:00 2001 From: "Claude Haiku 4.5 (1M context)" Date: Sat, 7 Nov 2026 08:12:33 +0100 Subject: [PATCH 2/2] Chore(twin,#16638): re-attestation des 9 paires de jumeaux de la tranche Search/Part3-Cas-pratiques Les 14 carnets de la tranche accent sont modifies (blob SHA change) : les paires concernees doivent etre re-attestees, sinon la garde de parite les declare DRIFT. Ordre respecte : `--update` passe EN DERNIER, apres le commit de contenu (regle #8957). Co-Authored-By: Claude Haiku 5.5 --- .../0021-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0027-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0027-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0013-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0012-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0018-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0019-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0016-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ .../0013-2026-11-07-myia-po-2027-CoursIA-2.yaml | 6 ++++++ 9 files changed, 54 insertions(+) create mode 100644 scripts/notebook_tools/twin_pairs.d/app-12-connectfour/0021-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-14-connectfour-adversarial/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-15-sportsscheduling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-17-vrp-logistics/0012-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0018-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-2-graphcoloring/0019-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-20-sudokubenchmark/0016-2026-11-07-myia-po-2027-CoursIA-2.yaml create mode 100644 scripts/notebook_tools/twin_pairs.d/app-5-timetabling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml diff --git a/scripts/notebook_tools/twin_pairs.d/app-12-connectfour/0021-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-12-connectfour/0021-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..11a35c64791 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-12-connectfour/0021-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: 4c08351ca9283a2e7822dc627e8261fae2bca2f1 +csharp_sha: 19ab0b4b61e912891ef249889a0fcaf94d0d1688 +content_python_sha: 73d1afef29c9f7476e3fbec47f8ae4847a84b0315149af0126206324f35d325c +content_csharp_sha: 982fede9ecad8bbac865f40994b2d9a9fbe35741f3375a7db37f21aa5f4865ca diff --git a/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..ab3b7e69ce0 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: cbfba74f87d529291c42a9926745ab015bd9b1bb +csharp_sha: 38fa5934713c9bdd73c75e9f99e07c286eebfc6c +content_python_sha: e23a2caa5afc72da83e864300b42583199c45b3102829e0a82f4ef52403ef13f +content_csharp_sha: 2afac5d897ccac7b5cb985ec76e64d7c67bfff88c298a00b97283f449ae50808 diff --git a/scripts/notebook_tools/twin_pairs.d/app-14-connectfour-adversarial/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-14-connectfour-adversarial/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..e1172341124 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-14-connectfour-adversarial/0027-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: 97e66aa2bdf17d6e97a0419dbd91583566a3f696 +csharp_sha: 3927d2a6c90bdf2da4ec67e2d609f160638bbe89 +content_python_sha: af5cecf2232780aecc153847b3f3b0437475cf8cdc61d2d753e34abd17612bf5 +content_csharp_sha: 3ece1942b0afa142b9e9878f972cf948a2597228712aaf254c65135010642051 diff --git a/scripts/notebook_tools/twin_pairs.d/app-15-sportsscheduling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-15-sportsscheduling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..1dfeb793968 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-15-sportsscheduling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: 1581ee42bca9977b2f20d4d6c99738ea3a89c27a +csharp_sha: b4acf01190968339c54266f6e3217449ab0d9bbe +content_python_sha: 2b40e5346570bfd20fdcbb3ab81e315aaa0029f484801092f640156aa16f2e14 +content_csharp_sha: 6144a6228d74903dda5c5fb8e43d0678281896d985db1208d748a50a6cb2aaae diff --git a/scripts/notebook_tools/twin_pairs.d/app-17-vrp-logistics/0012-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-17-vrp-logistics/0012-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..9c83f453ec7 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-17-vrp-logistics/0012-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: a55b01d5b32c7456386f9a5383bdb7412e097f75 +csharp_sha: e810a6425c227742a060cff82bec573123633658 +content_python_sha: 6a23884849c28a2d0fcd88dfb7c3fb1329ea1a3f00b6a116deccaecc913779c7 +content_csharp_sha: f1cd9a4988ed34d7b48c8fe67a1711576f4dc4837afd547d5951ddf9875b6cd4 diff --git a/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0018-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0018-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..3f29fe12f77 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0018-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: ea7f1dbb7013175aa9fb1f98d675a55d6ee7d3d8 +csharp_sha: 66bbb6622bb52f3d571c6684f3ae8a18e9558575 +content_python_sha: 1dbf75d2818d6774edd6c1b141010e56767549ed78d44d8d6755117645d688ad +content_csharp_sha: 6c31a9d86dc819889214b84d1625589f0686a4ca7cc204eb1897a80161007d29 diff --git a/scripts/notebook_tools/twin_pairs.d/app-2-graphcoloring/0019-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-2-graphcoloring/0019-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..4e75c4457fa --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-2-graphcoloring/0019-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: 3269fa87ba093d58872955f171463ecd59e93ee0 +csharp_sha: b06029569e2c1ce03f1328ec455b4811f4f07a5c +content_python_sha: d1bd932ade573e6d0530d2b587ba82773d4f79bc07b125353dabed49f9383e42 +content_csharp_sha: b11b9c8ab57735f7c8ca7965d821237f6bc48a89e857ad27a62b7ca1250118ff diff --git a/scripts/notebook_tools/twin_pairs.d/app-20-sudokubenchmark/0016-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-20-sudokubenchmark/0016-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..b6fb5377861 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-20-sudokubenchmark/0016-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: a113e326d56e90ec274fd7beaf0267984970b0e5 +csharp_sha: 10c14ff514da69573b24041708d13a8a92c63c74 +content_python_sha: cd4bbbf14ce15c4082ee9f10aab8c1598946ded916219468f4ab52f499da8048 +content_csharp_sha: fc2251e3471dcf16b800f52f232c5b57ab9a44df12fa12d4967c30754077169c diff --git a/scripts/notebook_tools/twin_pairs.d/app-5-timetabling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-5-timetabling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml new file mode 100644 index 00000000000..7e4155be9e8 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-5-timetabling/0013-2026-11-07-myia-po-2027-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-11-07' +by: myia-po-2027-CoursIA-2 +python_sha: 8d01acd8d4c321f8b062643222aa852433b3d4eb +csharp_sha: 67de733d946249951ec0b625b1fdfc5c97e1eaa3 +content_python_sha: f172dfcd40bad41e146003a8fa2f05c1ec147b61d53303ef9a595b63ccb3601d +content_csharp_sha: 08a09b91ec06dabce6fe62c4432bbaaea5dddad2cf498218d8446f994d181c40