diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-18b-HyperparameterTuning-Python.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-18b-HyperparameterTuning-Python.ipynb index 8d611dc2307..d768e8dd867 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-18b-HyperparameterTuning-Python.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-18b-HyperparameterTuning-Python.ipynb @@ -7,13 +7,13 @@ "source": [ "<< [App-17b VRP-Logistics (Python)](App-17b-VRP-Logistics-Python.ipynb) | [Index Search](../README.md) | [App-18 HyperparameterTuning (Python OR-Tools/Optuna)](App-18-HyperparameterTuning.ipynb) >>\n", "\n", - "# App-18b : Optimisation d'Hyperparametres (Python — From-Scratch)\n", + "# App-18b : Optimisation d'Hyperparamètres (Python — From-Scratch)\n", "\n", - "> **Twin Python** de [`App-18b-HyperparameterTuning-CSharp.ipynb`](App-18b-HyperparameterTuning-CSharp.ipynb). Le jumeau Python existant ([`App-18`](App-18-HyperparameterTuning.ipynb)) utilise scikit-learn + Optuna. Cette PR livre un **twin Python from-scratch** (numpy pur) aligne sur la version C# BCL pure : k-NN from-scratch + Grid/Random + **Bayesian Optimization avec Gaussian Process + Expected Improvement** + **Algorithme Genetique** + **Particle Swarm Optimization**, avec pont de verification SOTA Optuna.\n", + "> **Twin Python** de [`App-18b-HyperparameterTuning-CSharp.ipynb`](App-18b-HyperparameterTuning-CSharp.ipynb). Le jumeau Python existant ([`App-18`](App-18-HyperparameterTuning.ipynb)) utilise scikit-learn + Optuna. Cette PR livre un **twin Python from-scratch** (numpy pur) aligné sur la version C# BCL pure : k-NN from-scratch + Grid/Random + **Bayesian Optimization avec Gaussian Process + Expected Improvement** + **Algorithme Génétique** + **Particle Swarm Optimization**, avec pont de vérification SOTA Optuna.\n", "\n", "## Pourquoi un twin from-scratch ?\n", "\n", - "Le marathon [EPIC #4956](https://github.com/jsboige/CoursIA/issues/4956) vise la parite .NET ⇄ Python des series de notebooks. Pour App-17b, le jumeau Python (`App-17b-VRP-Logistics-Python`) a ete ajoute pour offrir la version Python from-scratch a cote de la version OR-Tools. Le meme gap existait pour App-18 : seul le twin Python OR-Tools/Optuna etait present. Cette PR ferme le gap avec une implementation numpy pure des algorithmes classiques d'optimisation d'hyperparametres." + "Le marathon [EPIC #4956](https://github.com/jsboige/CoursIA/issues/4956) vise la parité .NET ⇄ Python des séries de notebooks. Pour App-17b, le jumeau Python (`App-17b-VRP-Logistics-Python`) a été ajouté pour offrir la version Python from-scratch à côté de la version OR-Tools. Le même gap existait pour App-18 : seul le twin Python OR-Tools/Optuna était présent. Cette PR ferme le gap avec une implémentation numpy pure des algorithmes classiques d'optimisation d'hyperparamètres." ] }, { @@ -23,9 +23,9 @@ "source": [ "## Objectifs d'apprentissage\n", "\n", - "1. **Formaliser** le tuning d'hyperparametres comme un probleme d'optimisation black-box : un k-NN avec 3 hyperparametres (`k`, `distancePower`, `weightBlend`) et un objectif **CV 3-fold**.\n", - "2. **Comparer** 5 strategies : Grid Search, Random Search, Bayesian Optimization (Gaussian Process + Expected Improvement), Algorithme Genetique, Particle Swarm Optimization.\n", - "3. **Verifier** le from-scratch contre la bibliotheque SOTA **Optuna** (pont de mesure cellule 12).\n", + "1. **Formaliser** le tuning d'hyperparamètres comme un problème d'optimisation black-box : un k-NN avec 3 hyperparamètres (`k`, `distancePower`, `weightBlend`) et un objectif **CV 3-fold**.\n", + "2. **Comparer** 5 stratégies : Grid Search, Random Search, Bayesian Optimization (Gaussian Process + Expected Improvement), Algorithme Génétique, Particle Swarm Optimization.\n", + "3. **Vérifier** le from-scratch contre la bibliothèque SOTA **Optuna** (pont de mesure cellule 12).\n", "4. **Visualiser** les courbes de convergence et la carte de chaleur 2D de l'objectif." ] }, @@ -34,9 +34,9 @@ "id": "83857a33", "metadata": {}, "source": [ - "## 1. Configuration et jeu de donnees\n", + "## 1. Configuration et jeu de données\n", "\n", - "On genere un jeu de donnees de **classification binaire 2D** deterministe (deux amas gaussiens chevauchants, pour que la precision du k-NN depende sensiblement des hyperparametres)." + "On génère un jeu de données de **classification binaire 2D** déterministe (deux amas gaussiens chevauchants, pour que la précision du k-NN dépende sensiblement des hyperparamètres)." ] }, { @@ -115,14 +115,14 @@ "id": "8bee9a34", "metadata": {}, "source": [ - "## 2. Modele cible : k-NN from-scratch et objectif (CV 3-fold)\n", + "## 2. Modèle cible : k-NN from-scratch et objectif (CV 3-fold)\n", "\n", - "Le k-NN est le modele le plus simple a implementer from-scratch et suffit a definir un objectif **reel** (precision de classification) que toutes les strategies vont optimiser. L'objectif est l'**accuracy moyenne sur 3-fold CV stratifie**.\n", + "Le k-NN est le modèle le plus simple à implémenter from-scratch et suffit à définir un objectif **réel** (précision de classification) que toutes les stratégies vont optimiser. L'objectif est l'**accuracy moyenne sur 3-fold CV stratifié**.\n", "\n", - "Les hyperparametres a optimiser :\n", + "Les hyperparamètres à optimiser :\n", "- `k` (entier impair, 1..21) : nombre de voisins\n", - "- `distancePower` (reel, 1..4) : exposant de la distance de Minkowski (1 = Manhattan, 2 = Euclidien)\n", - "- `weightBlend` (reel, 0..1) : melange poids uniforme / poids par inverse-distance (0 = uniforme, 1 = full inverse-distance)" + "- `distancePower` (réel, 1..4) : exposant de la distance de Minkowski (1 = Manhattan, 2 = Euclidien)\n", + "- `weightBlend` (réel, 0..1) : mélange poids uniforme / poids par inverse-distance (0 = uniforme, 1 = full inverse-distance)" ] }, { @@ -198,9 +198,9 @@ "id": "b9240b95", "metadata": {}, "source": [ - "## 3. Methode de reference - Grid Search\n", + "## 3. Méthode de référence - Grid Search\n", "\n", - "**Principe** : explorer systematiquement un sous-ensemble de combinaisons de l'espace. Exhaustif mais **exponentiel** : 5 valeurs par dimension x 3 dimensions = 125 evaluations." + "**Principe** : explorer systématiquement un sous-ensemble de combinaisons de l'espace. Exhaustif mais **exponentiel** : 5 valeurs par dimension x 3 dimensions = 125 évaluations." ] }, { @@ -257,9 +257,9 @@ "id": "7c3f38c9", "metadata": {}, "source": [ - "## 4. Methode de reference - Random Search\n", + "## 4. Méthode de référence - Random Search\n", "\n", - "**Principe** (Bergstra & Bengio, 2012) : echantillonner uniformement dans l'espace. Contre-intuitivement, **aussi efficace que Grid Search** a budget egal si seulement quelques dimensions importent." + "**Principe** (Bergstra & Bengio, 2012) : échantillonner uniformément dans l'espace. Contre-intuitivement, **aussi efficace que Grid Search** à budget égal si seulement quelques dimensions importent." ] }, { @@ -316,7 +316,7 @@ "source": [ "### Exercice 1 : Vitesse de convergence\n", "\n", - "Ecrire `iterations_to_threshold(history, fraction)` qui retourne le **nombre d'evaluations** necessaires pour atteindre `fraction x optimum_final` de la meilleure valeur. Comparer Grid vs Random vs les methodes sophistiqueques sur ce critere." + "Écrire `iterations_to_threshold(history, fraction)` qui retourne le **nombre d'évaluations** nécessaires pour atteindre `fraction x optimum_final` de la meilleure valeur. Comparer Grid vs Random vs les méthodes sophistiqueques sur ce critère." ] }, { @@ -349,7 +349,7 @@ "source": [ "## 5. Vedette - Bayesian Optimization (Gaussian Process + Expected Improvement)\n", "\n", - "**Principe** : modeliser la fonction-objectif couteuse par un **surrogate** probabiliste - un **Gaussian Process** a noyau RBF - et choisir le prochain point en maximisant l'**Expected Improvement** (EI) sur le surrogate." + "**Principe** : modéliser la fonction-objectif coûteuse par un **surrogate** probabiliste - un **Gaussian Process** à noyau RBF - et choisir le prochain point en maximisant l'**Expected Improvement** (EI) sur le surrogate." ] }, { @@ -463,7 +463,7 @@ "id": "cell-bo-72d9369e", "metadata": {}, "source": [ - "**Pourquoi Bayes sous-performe-t-il ici (0.725 < Grid 0.733) ?** Le surrogate RBF du Gaussian Process **lisse le pic etroit de validation croisee** : sur ce paysage rugueux, l'optimum de k-NN tient sur environ un point-test par fold (un signal au niveau du bruit, +0.017 seulement). L'Expected Improvement explore donc une approximation lissee et manque le pic exact que GA et PSO atteignent par echantillonnage direct de la population. C'est le **compromis fondateur de l'optimisation bayesienne** : efficacite en echantillons (20 evaluations vs 125 pour Grid) au prix de la precision de peak-finding sur un paysage rugueux a faible signal. Ce n'est pas un defaut de l'algorithme -- c'est une propriete intrinseque du surrogate RBF." + "**Pourquoi Bayes sous-performe-t-il ici (0.725 < Grid 0.733) ?** Le surrogate RBF du Gaussian Process **lisse le pic étroit de validation croisée** : sur ce paysage rugueux, l'optimum de k-NN tient sur environ un point-test par fold (un signal au niveau du bruit, +0.017 seulement). L'Expected Improvement explore donc une approximation lissée et manque le pic exact que GA et PSO atteignent par échantillonnage direct de la population. C'est le **compromis fondateur de l'optimisation bayésienne** : efficacité en échantillons (20 évaluations vs 125 pour Grid) au prix de la précision de peak-finding sur un paysage rugueux à faible signal. Ce n'est pas un défaut de l'algorithme -- c'est une propriété intrinsèque du surrogate RBF." ] }, { @@ -473,7 +473,7 @@ "source": [ "### Exercice 2 : Fonction d'acquisition UCB (Upper Confidence Bound)\n", "\n", - "Le BayesianOptimizer ci-dessus utilise **Expected Improvement**. Implementer l'acquisition **UCB** complementaire, plus exploratoire : `UCB(x) = mu(x) + kappa * sig(x)`. Comparer la trajectoire EI vs UCB sur le meme budget." + "Le BayesianOptimizer ci-dessus utilise **Expected Improvement**. Implémenter l'acquisition **UCB** complémentaire, plus exploratoire : `UCB(x) = mu(x) + kappa * sig(x)`. Comparer la trajectoire EI vs UCB sur le même budget." ] }, { @@ -501,9 +501,9 @@ "id": "af5d422e", "metadata": {}, "source": [ - "## 6. Algorithme Genetique (GA)\n", + "## 6. Algorithme Génétique (GA)\n", "\n", - "**Principe** : faire evoluer une **population** de configurations via selection (tournoi), croisement (arithmetique), mutation (gaussienne decroissante) et elitisme." + "**Principe** : faire évoluer une **population** de configurations via sélection (tournoi), croisement (arithmétique), mutation (gaussienne décroissante) et élitisme." ] }, { @@ -584,12 +584,12 @@ "id": "24032017", "metadata": {}, "source": [ - "### Exercice 3 : Diversite d'une population genetique\n", + "### Exercice 3 : Diversité d'une population génétique\n", "\n", - "Une population trop homogene signifie que l'algorithme a converge prematurement. Implementer `population_diversity(pop)` :\n", - "- Etape 1 : barycentre de la population.\n", - "- Etape 2 : dispersion moyenne au barycentre.\n", - "- Etape 3 : surveiller la diversite au fil des generations." + "Une population trop homogène signifie que l'algorithme a convergé prématurément. Implémenter `population_diversity(pop)` :\n", + "- Étape 1 : barycentre de la population.\n", + "- Étape 2 : dispersion moyenne au barycentre.\n", + "- Étape 3 : surveiller la diversité au fil des générations." ] }, { @@ -619,7 +619,7 @@ "source": [ "## 7. Particle Swarm Optimization (PSO)\n", "\n", - "**Principe** : une nuee de particules ou chacune ajuste sa trajectoire selon (a) sa propre meilleure position (cognitive) et (b) la meilleure globale (sociale). Inertie + accelerations." + "**Principe** : une nuée de particules où chacune ajuste sa trajectoire selon (a) sa propre meilleure position (cognitive) et (b) la meilleure globale (sociale). Inertie + accélérations." ] }, { @@ -698,9 +698,9 @@ "id": "fa35d4cf", "metadata": {}, "source": [ - "## 8. Pont SOTA - verification contre Optuna\n", + "## 8. Pont SOTA - vérification contre Optuna\n", "\n", - "On verifie que le BO from-scratch tient la distance face a **Optuna** (bibliotheque SOTA de reference). Mesure : Optuna (**0.733**) devance le BO from-scratch (**0.725**, +1.1%) et égalise Grid/Random - le from-scratch est **pedagogique** (transparence du GP/EI) mais **pas SOTA en performance pure**. C'est precisement l'enseignement : un surrogate GP-from-scratch reste lisible mais n'égale pas l'optimisation C-level de TPE." + "On vérifie que le BO from-scratch tient la distance face à **Optuna** (bibliothèque SOTA de référence). Mesure : Optuna (**0.733**) devance le BO from-scratch (**0.725**, +1.1%) et égalise Grid/Random - le from-scratch est **pédagogique** (transparence du GP/EI) mais **pas SOTA en performance pure**. C'est précisément l'enseignement : un surrogate GP-from-scratch reste lisible mais n'égale pas l'optimisation C-level de TPE." ] }, { @@ -790,9 +790,9 @@ "id": "b63feb3b", "metadata": {}, "source": [ - "## 9. Comparaison des methodes - courbes de convergence\n", + "## 9. Comparaison des méthodes - courbes de convergence\n", "\n", - "On compare les **courbes de convergence** (meilleure accuracy observee en fonction du nombre d'evaluations) sur un budget comparable (~125 evaluations).\n", + "On compare les **courbes de convergence** (meilleure accuracy observée en fonction du nombre d'évaluations) sur un budget comparable (~125 évaluations).\n", "\n", "**Lecture attendue** : GA et PSO (**0.758**) dépassent les deux baselines Grid/Random (**0.733**) ; la Bayesian Optimization from-scratch à très petit budget (20 evals) reste légèrement en dessous (**0.725** vs 0.733) - l'efficacité-échantillons du GP-EI est un **régime** (budget et dimension favorables), pas une garantie à tout budget. Sur un objectif 3D bruité par la CV 5-fold, 20 evals ne suffisent pas au surrogate RBF pour exploiter le pic étroit que GA/PSO atteignent par population." ] @@ -884,7 +884,7 @@ "source": [ "## 10. Visualisation de l'espace de recherche\n", "\n", - "On visualise l'**objectif** (accuracy CV) sur une tranche 2D `(k, distancePower)` avec `weightBlend` fixe au meilleur trouve par BO." + "On visualise l'**objectif** (accuracy CV) sur une tranche 2D `(k, distancePower)` avec `weightBlend` fixé au meilleur trouvé par BO." ] }, { @@ -938,15 +938,15 @@ "source": [ "## Conclusion\n", "\n", - "Ce notebook ferme le **gap b-variante App-18** pour le marathon de parite .NET ⇄ Python (EPIC [#4956](https://github.com/jsboige/CoursIA/issues/4956)). Le jumeau Python existant ([`App-18`](App-18-HyperparameterTuning.ipynb)) utilise scikit-learn + Optuna ; ce nouveau jumeau Python propose une version **from-scratch** (numpy pur) alignee sur le jumeau C# BCL pure ([`App-18b`](App-18b-HyperparameterTuning-CSharp.ipynb)).\n", + "Ce notebook ferme le **gap b-variante App-18** pour le marathon de parité .NET ⇄ Python (EPIC [#4956](https://github.com/jsboige/CoursIA/issues/4956)). Le jumeau Python existant ([`App-18`](App-18-HyperparameterTuning.ipynb)) utilise scikit-learn + Optuna ; ce nouveau jumeau Python propose une version **from-scratch** (numpy pur) alignée sur le jumeau C# BCL pure ([`App-18b`](App-18b-HyperparameterTuning-CSharp.ipynb)).\n", "\n", - "**Resultats cles** :\n", + "**Résultats clés** :\n", "- **GA et PSO** (**0.758**) dépassent nettement les deux baselines Grid/Random (**0.733**) - c'est la discrimination que l'anisotropie des amas rend visible.\n", "- **Bayesian Optimization** from-scratch à très petit budget (20 evals, **0.725**) reste légèrement sous les baselines : l'efficacité-échantillons du GP-EI est un **régime** (budget/dimension favorables), pas une garantie à tout budget - leçon plus utile qu'une victoire annoncée.\n", - "- Le pont **Optuna** (cellule 12) mesure l'ecart avec la SOTA library : Optuna (**0.733**) égalise Grid/Random sans les dépasser, et devance le BO from-scratch de +1.1% (TPE optimise C-level).\n", - "- **Verdict SOTA-OK** ([EPIC #3801](https://github.com/jsboige/CoursIA/issues/3801)) : Optuna est proprement invoque comme verification independante, l'ecart est mesure honnetement. Le from-scratch est pedagogiquement justifie (transparence GP, EI acquisition) ; Optuna est industriellement optimise.\n", + "- Le pont **Optuna** (cellule 12) mesure l'écart avec la SOTA library : Optuna (**0.733**) égalise Grid/Random sans les dépasser, et devance le BO from-scratch de +1.1% (TPE optimisé C-level).\n", + "- **Verdict SOTA-OK** ([EPIC #3801](https://github.com/jsboige/CoursIA/issues/3801)) : Optuna est proprement invoqué comme vérification indépendante, l'écart est mesuré honnêtement. Le from-scratch est pédagogiquement justifié (transparence GP, EI acquisition) ; Optuna est industriellement optimisé.\n", "\n", - "**Parite pedagogique** : les 5 methodes (Grid, Random, BO, GA, PSO) sont presentes dans les deux jumeaux Python et C#, avec les memes 3 exercices (IterationsToThreshold, UCB acquisition, PopulationDiversity). Le lecteur peut comparer les implementations et observer les idiomes Python (numpy, list comprehensions) vs C# (LINQ, delegates, static methods)." + "**Parité pédagogique** : les 5 méthodes (Grid, Random, BO, GA, PSO) sont présentes dans les deux jumeaux Python et C#, avec les mêmes 3 exercices (IterationsToThreshold, UCB acquisition, PopulationDiversity). Le lecteur peut comparer les implémentations et observer les idiomes Python (numpy, list comprehensions) vs C# (LINQ, delegates, static methods)." ] } ], diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-33-RushHour-Admissible-Astar-Python.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-33-RushHour-Admissible-Astar-Python.ipynb index ed409f2b52a..8d445c689e8 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-33-RushHour-Admissible-Astar-Python.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-33-RushHour-Admissible-Astar-Python.ipynb @@ -14,21 +14,21 @@ "tags": [] }, "source": [ - "# Search App-33 — Rush Hour (Quindene) : l'A* admissible sur un puzzle a glissement\n", + "# Search App-33 — Rush Hour (Quindene) : l'A* admissible sur un puzzle à glissement\n", "\n", "**Navigation** : [<< App-34b 15-puzzle A*](App-34b-15Puzzle-Admissible-Astar-CSharp.ipynb) | [Index](../README.md)\n", "\n", - "Le **Rush Hour** (connu en France sous le nom **Quindene**) est un puzzle a glissement de reference pour la recherche dans un espace d'etats : une grille 6x6, une voiture rouge a extraire par la sortie en haut a droite, et une poignee de voitures qui se bloquent mutuellement. C'est le prolongement naturel du 15-puzzle, le puzzle a glissement de reference de la Partie 1 : comme lui, il offre un **espace d'etats net**, un **test de but clair** et des **heuristiques dont la force se mesure** (etats developpes, longueur de solution).\n", + "Le **Rush Hour** (connu en France sous le nom **Quindene**) est un puzzle à glissement de référence pour la recherche dans un espace d'états : une grille 6x6, une voiture rouge à extraire par la sortie en haut à droite, et une poignée de voitures qui se bloquent mutuellement. C'est le prolongement naturel du 15-puzzle, le puzzle à glissement de référence de la Partie 1 : comme lui, il offre un **espace d'états net**, un **test de but clair** et des **heuristiques dont la force se mesure** (états développés, longueur de solution).\n", "\n", - "Ce carnet pose le puzzle **from scratch** en Python pur (stdlib : `heapq`, `collections`, `random` — aucun solveur industriel) et y confronte trois algorithmes de recherche, sur un jeu d'instances a la difficulte controlable :\n", + "Ce carnet pose le puzzle **from scratch** en Python pur (stdlib : `heapq`, `collections`, `random` — aucun solveur industriel) et y confronte trois algorithmes de recherche, sur un jeu d'instances à la difficulté contrôlable :\n", "\n", - "- **BFS** — optimale en nombre de coups, mais elle developpe tout le frontiere ;\n", - "- **A\\*** — avec une **heuristique admissible** (les voitures qui bloquent la rouge) : optimal **et** nettement moins d'etats developpes ;\n", + "- **BFS** — optimale en nombre de coups, mais elle développe tout le frontière ;\n", + "- **A\\*** — avec une **heuristique admissible** (les voitures qui bloquent la rouge) : optimal **et** nettement moins d'états développés ;\n", "- **recherche gloutonne** — suit l'heuristique, rapide mais **sous-optimale** ;\n", - "- et un **benchmark comparatif** : sur un jeu de 6 instances distinctes a la difficulte comparable, le tableau **etats developpes x longueur de solution** par algorithme est le resultat mesure du carnet.\n", + "- et un **benchmark comparatif** : sur un jeu de 6 instances distinctes à la difficulté comparable, le tableau **états développés x longueur de solution** par algorithme est le résultat mesuré du carnet.\n", "\n", - "**Pre-requis** : la Partie 1 de la serie Search (espaces d'etats, BFS/A* admissible — le 15-puzzle y est le terrain d'essai) et la Partie 2.\n", - "**References** : IDA* (Korf 1985) ; le puzzle Rush Hour (Hider, 2003 — benchmarks `rush` / `rvect`) ; heuristiques admissibles pour les puzzles a glissement." + "**Pré-requis** : la Partie 1 de la série Search (espaces d'états, BFS/A* admissible — le 15-puzzle y est le terrain d'essai) et la Partie 2.\n", + "**Références** : IDA* (Korf 1985) ; le puzzle Rush Hour (Hider, 2003 — benchmarks `rush` / `rvect`) ; heuristiques admissibles pour les puzzles à glissement." ] }, { @@ -103,11 +103,11 @@ "tags": [] }, "source": [ - "## 1. L'espace d'etats : etats, deplacements, test de but\n", + "## 1. L'espace d'états : états, déplacements, test de but\n", "\n", - "Un **etat** est la position de toutes les voitures. Chaque voiture est un tuple `(ligne, col, orientation, est_rouge)` : pour une voiture horizontale, `(r, c)` est sa cellule de gauche (elle occupe `(r,c)` et `(r,c+1)`) ; pour une verticale, c'est sa cellule du haut.\n", + "Un **état** est la position de toutes les voitures. Chaque voiture est un tuple `(ligne, col, orientation, est_rouge)` : pour une voiture horizontale, `(r, c)` est sa cellule de gauche (elle occupe `(r,c)` et `(r,c+1)`) ; pour une verticale, c'est sa cellule du haut.\n", "\n", - "Un **deplacement** glisse une voiture le long de son axe vers toutes les positions vides atteignables : faire glisser une voiture, quelle que soit la distance, compte pour **un coup** (c'est la regle du puzzle). Le **but** est atteint quand la voiture rouge occupe les deux cases du haut a droite, `(0,4)` et `(0,5)`.\n" + "Un **déplacement** glisse une voiture le long de son axe vers toutes les positions vides atteignables : faire glisser une voiture, quelle que soit la distance, compte pour **un coup** (c'est la règle du puzzle). Le **but** est atteint quand la voiture rouge occupe les deux cases du haut à droite, `(0,4)` et `(0,5)`.\n" ] }, { @@ -221,7 +221,7 @@ "tags": [] }, "source": [ - "La grille est lue : la voiture rouge (`R`) est en haut, la sortie est a droite, et les autres voitures (`-` horizontales, `|` verticales) tiennent la grille. `neighbors` enumere tous les glissements legaux en un coup ; `is_goal` teste si la rouge est a la sortie.\n" + "La grille est lue : la voiture rouge (`R`) est en haut, la sortie est à droite, et les autres voitures (`-` horizontales, `|` verticales) tiennent la grille. `neighbors` énumère tous les glissements légaux en un coup ; `is_goal` teste si la rouge est à la sortie.\n" ] }, { @@ -238,9 +238,9 @@ "tags": [] }, "source": [ - "## 2. Instances : une position de base + generation par scramble\n", + "## 2. Instances : une position de base + génération par scramble\n", "\n", - "Plutot que de chercher a la main une position resolable, on **genere** des instances **garanties resolables** : on part d'une **position de base** (un enchevêtrement donné, resolable en 3 coups) et on lui applique quelques glissements **alatoires** — l'inverse de cette suite est, par construction, un chemin vers le but. C'est exactement la methode par laquelle on controle la difficulte d'un puzzle : la position de base porte le caractere « dur », le scramble ne fait que decliner des variantes distinctes et resolables.\n" + "Plutôt que de chercher à la main une position résolable, on **génère** des instances **garanties résolables** : on part d'une **position de base** (un enchevêtrement donné, résolable en 3 coups) et on lui applique quelques glissements **alatoires** — l'inverse de cette suite est, par construction, un chemin vers le but. C'est exactement la méthode par laquelle on contrôle la difficulté d'un puzzle : la position de base porte le caractère « dur », le scramble ne fait que décliner des variantes distinctes et résolables.\n" ] }, { @@ -321,7 +321,7 @@ "tags": [] }, "source": [ - "La position de depart est lue : la rouge est en bas a gauche, eloignee de la sortie, et deux voitures verticales (`|`) lui barrent la ligne 0 en colonnes 2 et 4 — elle doit d'abord les ecarter. Cette instance est **resolable** (en 3 coups, comme on va le verifier en la resolant) ; le scramble generera ensuite des variantes distinctes de meme difficulte pour le benchmark.\n" + "La position de départ est lue : la rouge est en bas à gauche, éloignée de la sortie, et deux voitures verticales (`|`) lui barrent la ligne 0 en colonnes 2 et 4 — elle doit d'abord les écarter. Cette instance est **résolable** (en 3 coups, comme on va le vérifier en la résolant) ; le scramble générera ensuite des variantes distinctes de même difficulté pour le benchmark.\n" ] }, { @@ -340,7 +340,7 @@ "source": [ "## 3. BFS — l'optimum en nombre de coups (baseline)\n", "\n", - "Le **BFS** explore l'espace par niveaux : il garantit de trouver une solution **optimale** (le plus petit nombre de coups) car il atteint chaque etat par le chemin le plus court. Son prix : il developpe l'integralite du frontiere explore, sans aucune information sur la direction du but. C'est notre **baseline** de reference.\n" + "Le **BFS** explore l'espace par niveaux : il garantit de trouver une solution **optimale** (le plus petit nombre de coups) car il atteint chaque état par le chemin le plus court. Son prix : il développe l'intégralité du frontière exploré, sans aucune information sur la direction du but. C'est notre **baseline** de référence.\n" ] }, { @@ -412,7 +412,7 @@ "tags": [] }, "source": [ - "Le BFS retrouve une solution **optimale** mais en developpant un nombre d'etats bien superieur au necessaire : il ne sait pas ou est le but, il balaye tout le frontiere. C'est exactement le defaut qu'une heuristique admissible doit corriger.\n" + "Le BFS retrouve une solution **optimale** mais en développant un nombre d'états bien supérieur au nécessaire : il ne sait pas où est le but, il balaye tout le frontière. C'est exactement le défaut qu'une heuristique admissible doit corriger.\n" ] }, { @@ -431,7 +431,7 @@ "source": [ "## 4. A* avec heuristique admissible\n", "\n", - "L'**heuristique** que nous posons est simple et **admissible** : elle compte le nombre de voitures (hors la rouge) qui occupent la **ligne 0 a droite de la voiture rouge**. Pourquoi admissible ? Pour que la rouge atteigne la sortie, **chaque** une de ces voitures doit etre deplacee **au moins une fois** hors de sa trajectoire. Le nombre de ces voitures est donc une **borne inferieure** au nombre de coups restants — l'A* qui l'utilise reste **optimal** (il ne coupe jamais une solution meilleure), tout en focalisant l'exploration vers le but.\n" + "L'**heuristique** que nous posons est simple et **admissible** : elle compte le nombre de voitures (hors la rouge) qui occupent la **ligne 0 à droite de la voiture rouge**. Pourquoi admissible ? Pour que la rouge atteigne la sortie, **chaque** une de ces voitures doit être déplacée **au moins une fois** hors de sa trajectoire. Le nombre de ces voitures est donc une **borne inférieure** au nombre de coups restants — l'A* qui l'utilise reste **optimal** (il ne coupe jamais une solution meilleure), tout en focalisant l'exploration vers le but.\n" ] }, { @@ -529,7 +529,7 @@ "tags": [] }, "source": [ - "L'A* retrouve **la meme longueur de solution optimale** que le BFS (l'heuristique est admissible, l'optimalite est preservee) en developpant **nettement moins d'etats** : c'est tout le rendement d'une heuristique admissible. Le rapport developpe ci-dessus est le chiffre central de la comparaison.\n" + "L'A* retrouve **la même longueur de solution optimale** que le BFS (l'heuristique est admissible, l'optimalité est préservée) en développant **nettement moins d'états** : c'est tout le rendement d'une heuristique admissible. Le rapport développé ci-dessus est le chiffre central de la comparaison.\n" ] }, { @@ -548,7 +548,7 @@ "source": [ "## 5. Recherche gloutonne — rapide, mais sous-optimale\n", "\n", - "La **recherche gloutonne** ne garde aucun compte du cout deja parcouru : a chaque etape elle part vers le voisin dont l'heuristique est la **plus faible** (le moins de bloqueurs). Plus simple que l'A* (elle ne s'embarrasse pas de l'optimalite), elle **abandonne la garantie d'optimalite** : elle peut livrer une solution nettement plus longue, voire s'engager dans un cul-de-sac.\n" + "La **recherche gloutonne** ne garde aucun compte du coût déjà parcouru : à chaque étape elle part vers le voisin dont l'heuristique est la **plus faible** (le moins de bloqueurs). Plus simple que l'A* (elle ne s'embarrasse pas de l'optimalité), elle **abandonne la garantie d'optimalité** : elle peut livrer une solution nettement plus longue, voire s'engager dans un cul-de-sac.\n" ] }, { @@ -631,7 +631,7 @@ "tags": [] }, "source": [ - "Le contraste est la lecon : le glouton **perd l'optimalite** — sur cette instance sa solution est nettement plus longue que l'optimum (une centaine de coups contre 3), et il ne gagne pas en vitesse pour autant : il developpe plus d'etats que l'A*, car il suit le gradient d'heuristique au lieu de combiner cout parcouru et heuristique. L'A* est le meilleur compromis : optimal **et** econome en etats.\n" + "Le contraste est la leçon : le glouton **perd l'optimalité** — sur cette instance sa solution est nettement plus longue que l'optimum (une centaine de coups contre 3), et il ne gagne pas en vitesse pour autant : il développe plus d'états que l'A*, car il suit le gradient d'heuristique au lieu de combiner coût parcouru et heuristique. L'A* est le meilleur compromis : optimal **et** économe en états.\n" ] }, { @@ -648,9 +648,9 @@ "tags": [] }, "source": [ - "## 6. Benchmark comparatif — le resultat mesure\n", + "## 6. Benchmark comparatif — le résultat mesuré\n", "\n", - "Sur un **jeu de 6 instances distinctes**, nous mesurons pour chaque algorithme le **nombre d'etats developpes** et la **longueur de solution**. Pour garder une comparaison a **difficulte comparable**, on **selectionne** parmi les scrambles de la position de base les instances **non triviales** — celles ou le BFS developpe un volume d'etats significatif (au moins 100) — et on n'en retient que 6. Les instances trop faciles sont ecartees : a cette echelle, l'overhead de la structure de priorite de l'A* domine et masquerait le role de l'heuristique. C'est le tableau que le carnet doit produire : il rend visible, en chiffres, le role de l'heuristique admissible.\n" + "Sur un **jeu de 6 instances distinctes**, nous mesurons pour chaque algorithme le **nombre d'états développés** et la **longueur de solution**. Pour garder une comparaison à **difficulté comparable**, on **sélectionne** parmi les scrambles de la position de base les instances **non triviales** — celles où le BFS développe un volume d'états significatif (au moins 100) — et on n'en retient que 6. Les instances trop faciles sont écartées : à cette échelle, l'overhead de la structure de priorité de l'A* domine et masquerait le rôle de l'heuristique. C'est le tableau que le carnet doit produire : il rend visible, en chiffres, le rôle de l'heuristique admissible.\n" ] }, { @@ -742,11 +742,11 @@ "tags": [] }, "source": [ - "Le tableau porte le carnet : **BFS et A* livrent la meme solution optimale** (3 coups), mais **A* developpe systematiquement moins d'etats** — sur chacune des six instances, et en total (921 contre 2985, soit un rapport de 0,31 : le BFS developpe environ 3,2 fois plus d'etats). C'est le rendement mesuré de l'heuristique admissible.\n", + "Le tableau porte le carnet : **BFS et A* livrent la même solution optimale** (3 coups), mais **A* développe systématiquement moins d'états** — sur chacune des six instances, et en total (921 contre 2985, soit un rapport de 0,31 : le BFS développe environ 3,2 fois plus d'états). C'est le rendement mesuré de l'heuristique admissible.\n", "\n", - "Le **glouton**, lui, ne cherche pas : il livre a chaque ligne une solution **tres sous-optimale** (134 coups contre 3) et son exploration est **quasi constante** — 134 ou 135 etats sur les six instances, quelle que soit leur difficulte, la ou l'A* varie de 100 a 262. Ce n'est pas une economie d'etats, c'est la signature d'une recherche sans retour arriere : sur les deux instances les plus dures (#2 et #3), le glouton developpe meme *moins* d'etats que l'A* (135 contre 262, 134 contre 186) et paie cette sobriete apparente de quarante-cinq fois plus de coups (134 contre 3). Suivre un gradient d'heuristique pure, au lieu de combiner cout deja parcouru et heuristique comme le fait l'A*, c'est glisser vers la premiere solution venue, pas chercher. Le glouton ne gagne donc pas la course qu'il parait gagner : il ne developpe pas « plus » d'etats que l'A* a chaque ligne, il en developpe un nombre fixe, insensible a la difficulte — et c'est precisement ce qui le condamne.\n", + "Le **glouton**, lui, ne cherche pas : il livre à chaque ligne une solution **très sous-optimale** (134 coups contre 3) et son exploration est **quasi constante** — 134 ou 135 états sur les six instances, quelle que soit leur difficulté, là où l'A* varie de 100 à 262. Ce n'est pas une économie d'états, c'est la signature d'une recherche sans retour arrière : sur les deux instances les plus dures (#2 et #3), le glouton développe même *moins* d'états que l'A* (135 contre 262, 134 contre 186) et paie cette sobriété apparente de quarante-cinq fois plus de coups (134 contre 3). Suivre un gradient d'heuristique pure, au lieu de combiner coût déjà parcouru et heuristique comme le fait l'A*, c'est glisser vers la première solution venue, pas chercher. Le glouton ne gagne donc pas la course qu'il paraît gagner : il ne développe pas « plus » d'états que l'A* à chaque ligne, il en développe un nombre fixe, insensible à la difficulté — et c'est précisément ce qui le condamne.\n", "\n", - "Une note sur la mesure : les instances #4 et #6 portent cinq metriques identiques. Verifie : leurs cles d'etat sont distinctes (elles ne different que par la position d'une voiture arriere) et leurs ensembles d'etats visites different — 983 communs sur 1473 — pour une taille egale. La coincidence est donc dans la mesure, pas dans une instance dupliquee." + "Une note sur la mesure : les instances #4 et #6 portent cinq métriques identiques. Vérifié : leurs clés d'état sont distinctes (elles ne diffèrent que par la position d'une voiture arrière) et leurs ensembles d'états visités diffèrent — 983 communs sur 1473 — pour une taille égale. La coïncidence est donc dans la mesure, pas dans une instance dupliquée." ] }, { @@ -765,9 +765,9 @@ "source": [ "## 7. Exercices\n", "\n", - "Trois exercices, un par mecanisme du carnet : le test de but, l'heuristique admissible, le voisinage.\n", + "Trois exercices, un par mécanisme du carnet : le test de but, l'heuristique admissible, le voisinage.\n", "\n", - "**Politique de sortie.** Les cellules d'exercice ne produisent **aucune sortie** a l'execution, et c'est voulu : ce sont des `def`, et une definition de fonction n'affiche rien. Le `print(\"Exercice a completer\")` qu'elles contiennent vit dans le corps de la fonction et ne se joue que lorsqu'on l'appelle. Completez la fonction, puis appelez-la sur une instance — `is_goal_exo(base_hard())` par exemple — pour voir votre resultat : c'est cette sortie-la qui compte, pas celle du carnet." + "**Politique de sortie.** Les cellules d'exercice ne produisent **aucune sortie** à l'exécution, et c'est voulu : ce sont des `def`, et une définition de fonction n'affiche rien. Le `print(\"Exercice a completer\")` qu'elles contiennent vit dans le corps de la fonction et ne se joue que lorsqu'on l'appelle. Complétez la fonction, puis appelez-la sur une instance — `is_goal_exo(base_hard())` par exemple — pour voir votre résultat : c'est cette sortie-là qui compte, pas celle du carnet." ] }, { @@ -786,9 +786,9 @@ "source": [ "### Exercice 1 — Le test de but\n", "\n", - "Complete `is_goal_exo` : renvoyer `True` si la voiture rouge est bien a la sortie (horizontale, ligne 0, case gauche en colonne 4).\n", + "Complète `is_goal_exo` : renvoyer `True` si la voiture rouge est bien à la sortie (horizontale, ligne 0, case gauche en colonne 4).\n", "\n", - "**Indice** : recupere la voiture rouge avec `red_car`, puis verifie ses trois coordonnees `(ligne, col, orientation)`.\n" + "**Indice** : récupère la voiture rouge avec `red_car`, puis vérifie ses trois coordonnées `(ligne, col, orientation)`.\n" ] }, { @@ -836,9 +836,9 @@ "source": [ "### Exercice 2 — L'heuristique admissible\n", "\n", - "Reimplimente `heuristic_exo` : compter les voitures (hors la rouge) qui occupent la **ligne 0 a droite de la case droite de la rouge**.\n", + "Réimplimente `heuristic_exo` : compter les voitures (hors la rouge) qui occupent la **ligne 0 à droite de la case droite de la rouge**.\n", "\n", - "**Indice** : determine la colonne `red_right` de la case droite de la rouge, puis compte les voitures distinctes ayant au moins une cellule en `(0, c)` avec `c > red_right`.\n" + "**Indice** : détermine la colonne `red_right` de la case droite de la rouge, puis compte les voitures distinctes ayant au moins une cellule en `(0, c)` avec `c > red_right`.\n" ] }, { @@ -886,9 +886,9 @@ "source": [ "### Exercice 3 — Un voisinage\n", "\n", - "Complete `slide_exo` : pour une voiture donnee et un ensemble `occ` de cellules occupees, renvoyer la **liste des positions** atteignables par un glissement (les deux sens de l'axe).\n", + "Complète `slide_exo` : pour une voiture donnée et un ensemble `occ` de cellules occupées, renvoyer la **liste des positions** atteignables par un glissement (les deux sens de l'axe).\n", "\n", - "**Indice** : pour un sens, incremente un pas `k` tant que la cellule de tete du glissement est dans les bornes et absente de `occ` ; ajoute la nouvelle position a chaque pas valide.\n" + "**Indice** : pour un sens, incrémente un pas `k` tant que la cellule de tête du glissement est dans les bornes et absente de `occ` ; ajoute la nouvelle position à chaque pas valide.\n" ] }, { @@ -936,7 +936,7 @@ "source": [ "## Conclusion\n", "\n", - "Le Rush Hour est le terrain d'essai ideal du **triangle de la recherche** : le **BFS** est optimal mais depense ; l'**A\\*** avec une **heuristique admissible** (les bloqueurs de la rouge) est **a la fois optimal et econome** — c'est la lecon centrale, mesuree sur un jeu de 6 instances (921 etats contre 2985, soit 3,2 fois moins d'etats developpes) ; la **recherche gloutonne** explore un nombre d'etats quasi constant (134-135, quelle que soit l'instance) mais **sacrifie l'optimalite** (134 coups contre 3) : elle ne cherche pas, elle glisse. Choisir une heuristique, c'est choisir ou tomber dans ce triangle : l'admissibilite est la propriete qui permet de ne pas sacrifier l'optimalite. Ce carnet complete, avec le 15-puzzle de la Partie 1, la famille des puzzles a glissement de la serie et ferme la boucle sur les heuristiques admissibles introduites dans les Parties 1-2." + "Le Rush Hour est le terrain d'essai idéal du **triangle de la recherche** : le **BFS** est optimal mais dépense ; l'**A\\*** avec une **heuristique admissible** (les bloqueurs de la rouge) est **à la fois optimal et économe** — c'est la leçon centrale, mesurée sur un jeu de 6 instances (921 états contre 2985, soit 3,2 fois moins d'états développés) ; la **recherche gloutonne** explore un nombre d'états quasi constant (134-135, quelle que soit l'instance) mais **sacrifie l'optimalité** (134 coups contre 3) : elle ne cherche pas, elle glisse. Choisir une heuristique, c'est choisir où tomber dans ce triangle : l'admissibilité est la propriété qui permet de ne pas sacrifier l'optimalité. Ce carnet complète, avec le 15-puzzle de la Partie 1, la famille des puzzles à glissement de la série et ferme la boucle sur les heuristiques admissibles introduites dans les Parties 1-2." ] } ], diff --git a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-34b-15Puzzle-Admissible-Astar-CSharp.ipynb b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-34b-15Puzzle-Admissible-Astar-CSharp.ipynb index 76cf20648fa..5525ccd8d38 100644 --- a/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-34b-15Puzzle-Admissible-Astar-CSharp.ipynb +++ b/MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-34b-15Puzzle-Admissible-Astar-CSharp.ipynb @@ -20,15 +20,15 @@ "\n", "> **Twin C#** de `App-34-15Puzzle-Admissible-Astar-Python.ipynb` (issue #21752).\n", "> Marathon **.NET / Python** (#4956), volet **Search / Applications**.\n", - "> Kernel `.net-csharp` (.NET 9+) -- **aucun NuGet** : tout est en BCL, le carnet ne depend d'aucun reseau.\n", + "> Kernel `.net-csharp` (.NET 9+) -- **aucun NuGet** : tout est en BCL, le carnet ne dépend d'aucun réseau.\n", "\n", "Le **15-puzzle glissant** est l'exemple par lequel tout cours introduit l'A* : un espace\n", - "d'etats discret, un invariant de **resolvabilite** non trivial, et des heuristiques dont la\n", - "force se **mesure** (noeuds developpes, cout de solution).\n", + "d'états discret, un invariant de **résolvabilité** non trivial, et des heuristiques dont la\n", + "force se **mesure** (noeuds développés, coût de solution).\n", "\n", - "Ce carnet est le jumeau C# de la version Python : meme protocole, meme jeu de mesures, memes\n", - "constantes. Il **reconstruit** la semantique depuis zero -- encode, parite, heuristiques,\n", - "recherches -- et ne fait aucun appel a la version Python." + "Ce carnet est le jumeau C# de la version Python : même protocole, même jeu de mesures, mêmes\n", + "constantes. Il **reconstruit** la sémantique depuis zéro -- encode, parité, heuristiques,\n", + "recherches -- et ne fait aucun appel à la version Python." ] }, { @@ -202,18 +202,18 @@ }, "source": [ "***\n", - "## 1. L'espace d'etats -- (S, s0, A, T, G)\n", + "## 1. L'espace d'états -- (S, s0, A, T, G)\n", "\n", - "L'etat est une grille 4x4 : les cases 1 a 15 portent une tuile, la case `0` est le vide.\n", - "On l'**encode dans un `ulong`** (4 bits par case, `0` = vide) : un etat tient dans un entier,\n", - "ce qui rend les tables de hachage triviales et la comparaison d'etats constante.\n", + "L'état est une grille 4x4 : les cases 1 à 15 portent une tuile, la case `0` est le vide.\n", + "On l'**encode dans un `ulong`** (4 bits par case, `0` = vide) : un état tient dans un entier,\n", + "ce qui rend les tables de hachage triviales et la comparaison d'états constante.\n", "\n", - "- **Actions** : les quatre deplacements de la case vide (droite, gauche, bas, haut).\n", - "- **Transition** : echange du vide avec la tuile voisine.\n", - "- **But** : l'etat `1..15, 0` (rangee par rangee).\n", + "- **Actions** : les quatre déplacements de la case vide (droite, gauche, bas, haut).\n", + "- **Transition** : échange du vide avec la tuile voisine.\n", + "- **But** : l'état `1..15, 0` (rangée par rangée).\n", "\n", - "L'encodage n'est pas un detail d'implementation : c'est ce qui permet de mesurer des\n", - "**centaines de milliers** de noeuds developpes sans que le cout de la structure de donnees\n", + "L'encodage n'est pas un détail d'implémentation : c'est ce qui permet de mesurer des\n", + "**centaines de milliers** de noeuds développés sans que le coût de la structure de données\n", "domine la mesure." ] }, @@ -313,18 +313,18 @@ }, "source": [ "***\n", - "## 2. La resolvabilite -- l'invariant de parite\n", + "## 2. La résolvabilité -- l'invariant de parité\n", "\n", - "Une configuration du 15-puzzle n'est pas toujours resoluble, et **l'echec est muet** : la\n", - "recherche epuise l'espace sans jamais atteindre le but. Le discriminant est la **parite** :\n", + "Une configuration du 15-puzzle n'est pas toujours résoluble, et **l'échec est muet** : la\n", + "recherche épuise l'espace sans jamais atteindre le but. Le discriminant est la **parité** :\n", "\n", - "- on compte les **inversions** -- paires de tuiles dont l'ordre est inverse par rapport a l'ordre\n", - " final (la case vide est ignoree) ;\n", - "- on ajoute la **ligne de la case vide comptee depuis le bas** (1 a 4) ;\n", - "- pour une grille de largeur **paire** (4), la configuration est resoluble ssi la somme est\n", + "- on compte les **inversions** -- paires de tuiles dont l'ordre est inverse par rapport à l'ordre\n", + " final (la case vide est ignorée) ;\n", + "- on ajoute la **ligne de la case vide comptée depuis le bas** (1 à 4) ;\n", + "- pour une grille de largeur **paire** (4), la configuration est résoluble ssi la somme est\n", " **impaire**.\n", "\n", - "La regle se verifie par la mesure ci-dessous, sur trois proprietes independantes." + "La règle se vérifie par la mesure ci-dessous, sur trois propriétés indépendantes." ] }, { @@ -432,29 +432,29 @@ "***\n", "## 3. Deux heuristiques admissibles, et une recherche non admissible\n", "\n", - "Une heuristique est **admissible** quand elle ne surestime jamais le cout restant :\n", + "Une heuristique est **admissible** quand elle ne surestime jamais le coût restant :\n", "`h(s) <= d*(s)`. L'A* est alors **optimal** -- il renvoie le chemin le plus court -- mais son\n", - "cout depend de la force de `h`.\n", + "coût dépend de la force de `h`.\n", "\n", - "- **Manhattan** : somme des distances (verticale + horizontale) de chaque tuile a sa position\n", + "- **Manhattan** : somme des distances (verticale + horizontale) de chaque tuile à sa position\n", " finale. Admissible, mais elle ignore les obstacles *entre* les tuiles.\n", - "- **Manhattan + conflit lineaire** : deux tuiles qui occupent la meme ligne que leur position\n", + "- **Manhattan + conflit linéaire** : deux tuiles qui occupent la même ligne que leur position\n", " finale, mais dans un **ordre inverse**, doivent se croiser. Chaque tuile qui doit **quitter**\n", - " sa ligne (ou sa colonne) puis y revenir coute au moins **2 deplacements de plus**.\n", - " On compte le nombre **minimal** de tuiles a retirer de chaque ligne (ou colonne) pour que\n", + " sa ligne (ou sa colonne) puis y revenir coûte au moins **2 déplacements de plus**.\n", + " On compte le nombre **minimal** de tuiles à retirer de chaque ligne (ou colonne) pour que\n", " l'ordre relatif soit correct -- c'est la longueur de la sous-suite croissante la plus\n", " longue qui reste en place -- et on ajoute `2 x (ce nombre)`. L'heuristique reste admissible,\n", " mais elle est plus forte.\n", - " **Un piege de double comptage** : une tuile deja a sa place finale ne doit **ni** quitter sa\n", + " **Un piège de double comptage** : une tuile déjà à sa place finale ne doit **ni** quitter sa\n", " ligne **ni** quitter sa colonne. La compter dans les deux groupes lui ferait attribuer\n", - " `+4` deplacements qu'elle ne demande pas -- et l'heuristique cesserait d'etre admissible.\n", - " Le code ci-dessous **exclut** donc les tuiles deja a leur place ; c'est ce qui rend la\n", - " verification d'admissibilite du paragraphe 4 vraie.\n", - "- **A* pondere** (`f = g + w * h`, ici `w = 2`) : l'heuristique est **multipliee**, donc\n", - " n'est plus admissible. La recherche devient beaucoup plus rapide, mais le cout de la\n", - " solution peut **degrader**.\n", + " `+4` déplacements qu'elle ne demande pas -- et l'heuristique cesserait d'être admissible.\n", + " Le code ci-dessous **exclut** donc les tuiles déjà à leur place ; c'est ce qui rend la\n", + " vérification d'admissibilité du paragraphe 4 vraie.\n", + "- **A* pondéré** (`f = g + w * h`, ici `w = 2`) : l'heuristique est **multipliée**, donc\n", + " n'est plus admissible. La recherche devient beaucoup plus rapide, mais le coût de la\n", + " solution peut **dégrader**.\n", "\n", - "Les trois sont mesurees sur les memes puzzles, avec la meme graine." + "Les trois sont mesurées sur les mêmes puzzles, avec la même graine." ] }, { @@ -600,28 +600,28 @@ }, "source": [ "***\n", - "## 4. La mesure -- noeuds developpes x cout de solution\n", + "## 4. La mesure -- noeuds développés x coût de solution\n", "\n", - "Les puzzles sont produits par un **melange legal** de l'etat but : a chaque coup on deplace la\n", - "case vide au hasard, en interdisant de revenir immediatement en arriere. Cette generation est\n", - "**garantie solvable** (tout coup legal est reversible) et **deterministe** (graine fixe).\n", + "Les puzzles sont produits par un **mélange légal** de l'état but : à chaque coup on déplace la\n", + "case vide au hasard, en interdisant de revenir immédiatement en arrière. Cette génération est\n", + "**garantie solvable** (tout coup légal est réversible) et **déterministe** (graine fixe).\n", "\n", - "Un melange court laisse le puzzle **près du but** (l'espace de recherche est negligeable) ;\n", - "il faut des dizaines de coups pour obtenir des instances ou l'heuristique discrimine\n", - "reellement. Le protocole mesure donc quatre profondeurs de melange, trois puzzles chacune, et\n", + "Un mélange court laisse le puzzle **près du but** (l'espace de recherche est négligeable) ;\n", + "il faut des dizaines de coups pour obtenir des instances où l'heuristique discrimine\n", + "réellement. Le protocole mesure donc quatre profondeurs de mélange, trois puzzles chacune, et\n", "compare les trois recherches :\n", "\n", - "- **A\\* Manhattan** -- admissible, sert de **reference optimale** ;\n", - "- **A\\* Manhattan + conflit lineaire** -- admissible, plus forte ;\n", - "- **A\\* pondere (w = 2)** -- non admissible : plus rapide, cout potentiellement degrade.\n", + "- **A\\* Manhattan** -- admissible, sert de **référence optimale** ;\n", + "- **A\\* Manhattan + conflit linéaire** -- admissible, plus forte ;\n", + "- **A\\* pondéré (w = 2)** -- non admissible : plus rapide, coût potentiellement dégradé.\n", "\n", - "Le cout de reference est celui de l'A* avec Manhattan : l'heuristique etant admissible, c'est\n", - "le cout **optimal**. Chaque recherche est plafonnee (3 000 000 d'expansions) : si une recherche\n", - "n'aboutit pas, le puzzle est **ecarte entierement** -- les moyennes ne portent que sur les\n", - "puzzles que les **trois** recherches ont resolus, car comparer des moyennes calculees sur des\n", - "ensembles differents n'aurait aucun sens. Le tableau verifie ensuite, sur ces instances\n", - "communes, que le conflit lineaire **n'a pas degrade** le cout optimal (il reste admissible) et\n", - "que l'A* pondere, lui, **degrade** le cout sur au moins un puzzle." + "Le coût de référence est celui de l'A* avec Manhattan : l'heuristique étant admissible, c'est\n", + "le coût **optimal**. Chaque recherche est plafonnée (3 000 000 d'expansions) : si une recherche\n", + "n'aboutit pas, le puzzle est **écarté entièrement** -- les moyennes ne portent que sur les\n", + "puzzles que les **trois** recherches ont résolus, car comparer des moyennes calculées sur des\n", + "ensembles différents n'aurait aucun sens. Le tableau vérifie ensuite, sur ces instances\n", + "communes, que le conflit linéaire **n'a pas dégradé** le coût optimal (il reste admissible) et\n", + "que l'A* pondéré, lui, **dégrade** le coût sur au moins un puzzle." ] }, { @@ -892,13 +892,13 @@ "***\n", "## 5. Exercices\n", "\n", - "Les trois exercices sont des **stubs** : ils rendent une valeur neutre et le carnet s'execute de\n", - "bout en bout. A vous de les implementer.\n", + "Les trois exercices sont des **stubs** : ils rendent une valeur neutre et le carnet s'exécute de\n", + "bout en bout. À vous de les implémenter.\n", "\n", - "### Exercice 1 -- le test de resolvabilite\n", + "### Exercice 1 -- le test de résolvabilité\n", "\n", - "Ecrivez le test de parite : compter les inversions (en ignorant la case vide), ajouter la ligne\n", - "de la case vide comptee depuis le bas (1 a 4), et conclure." + "Écrivez le test de parité : compter les inversions (en ignorant la case vide), ajouter la ligne\n", + "de la case vide comptée depuis le bas (1 à 4), et conclure." ] }, { @@ -958,10 +958,10 @@ "tags": [] }, "source": [ - "### Exercice 2 -- le conflit lineaire au-dessus de Manhattan\n", + "### Exercice 2 -- le conflit linéaire au-dessus de Manhattan\n", "\n", - "Ecrivez le compte des conflits lineaires : pour chaque ligne et chaque colonne, collecter les\n", - "tuiles deja placees sur leur ligne (ou colonne) finale, puis compter le nombre **minimal** de\n", + "Écrivez le compte des conflits linéaires : pour chaque ligne et chaque colonne, collecter les\n", + "tuiles déjà placées sur leur ligne (ou colonne) finale, puis compter le nombre **minimal** de\n", "tuiles qu'il faut retirer pour que l'ordre relatif soit correct." ] }, @@ -1026,10 +1026,10 @@ "tags": [] }, "source": [ - "### Exercice 3 -- l'ecart d'optimalite d'un A* pondere\n", + "### Exercice 3 -- l'écart d'optimalité d'un A* pondéré\n", "\n", - "Un A* pondere utilise `f = g + w * h`. Pour `w = 1` il est optimal ; pour `w > 1` l'heuristique\n", - "n'est plus admissible et la solution trouvee peut couter plus cher. Mesurez l'ecart." + "Un A* pondéré utilise `f = g + w * h`. Pour `w = 1` il est optimal ; pour `w > 1` l'heuristique\n", + "n'est plus admissible et la solution trouvée peut coûter plus cher. Mesurez l'écart." ] }, { @@ -1144,28 +1144,28 @@ "***\n", "## Conclusion\n", "\n", - "Ce jumeau C# a reconstruit depuis zero le protocole du carnet Python (#21752) :\n", + "Ce jumeau C# a reconstruit depuis zéro le protocole du carnet Python (#21752) :\n", "\n", - "1. **l'espace d'etats** encode dans un `ulong` (4 bits par case) -- un etat tient dans un entier,\n", - " et la mesure des noeuds developpes ne depend pas de la structure de donnees ;\n", - "2. **la resolvabilite** par parite des inversions, verifiee par la mesure sur trois\n", - " proprietes independantes (moitie des configurations aleatoires, etat but, un coup legal) ;\n", - "3. **deux heuristiques admissibles** -- Manhattan, et Manhattan + conflit lineaire -- comparees\n", - " sur le **nombre de noeuds developpes** et le **cout de solution** ;\n", - "4. **un contraste non admissible** -- l'A* pondere (`w = 2`), qui divise le nombre de noeuds\n", - " developpes mais **degrade le cout** de la solution.\n", + "1. **l'espace d'états** encodé dans un `ulong` (4 bits par case) -- un état tient dans un entier,\n", + " et la mesure des noeuds développés ne dépend pas de la structure de données ;\n", + "2. **la résolvabilité** par parité des inversions, vérifiée par la mesure sur trois\n", + " propriétés indépendantes (moitié des configurations aléatoires, état but, un coup légal) ;\n", + "3. **deux heuristiques admissibles** -- Manhattan, et Manhattan + conflit linéaire -- comparées\n", + " sur le **nombre de noeuds développés** et le **coût de solution** ;\n", + "4. **un contraste non admissible** -- l'A* pondéré (`w = 2`), qui divise le nombre de noeuds\n", + " développés mais **dégrade le coût** de la solution.\n", "\n", - "Les trois exercices (parite, conflit lineaire, ecart d'optimalite d'un A* pondere) sont des\n", - "stubs : ils rendent une valeur neutre, le carnet s'execute de bout en bout.\n", + "Les trois exercices (parité, conflit linéaire, écart d'optimalité d'un A* pondéré) sont des\n", + "stubs : ils rendent une valeur neutre, le carnet s'exécute de bout en bout.\n", "\n", - "**Portee de la parite .NET / Python.** Les deux carnets partagent le **protocole** (meme\n", - "encodage 4 bits, meme test de parite, meme jeu de mesures : noeuds developpes et cout de\n", - "solution, meme constante de graine `42`). Ils ne partagent **pas** les instances tirees : le\n", - "generateur pseudo-aleatoire de .NET et celui de Python ne produisent pas la meme suite, donc\n", - "les **nombres** du tableau different d'un runtime a l'autre par construction. Ce qui est\n", - "**invariant** entre les deux, et qui est verifie par la mesure dans chaque carnet, ce sont les\n", - "**proprietes** : la parite, l'admissibilite du conflit lineaire (cout optimal inchange), et la\n", - "degradation du cout par l'A* pondere." + "**Portée de la parité .NET / Python.** Les deux carnets partagent le **protocole** (même\n", + "encodage 4 bits, même test de parité, même jeu de mesures : noeuds développés et coût de\n", + "solution, même constante de graine `42`). Ils ne partagent **pas** les instances tirées : le\n", + "générateur pseudo-aléatoire de .NET et celui de Python ne produisent pas la même suite, donc\n", + "les **nombres** du tableau diffèrent d'un runtime à l'autre par construction. Ce qui est\n", + "**invariant** entre les deux, et qui est vérifié par la mesure dans chaque carnet, ce sont les\n", + "**propriétés** : la parité, l'admissibilité du conflit linéaire (coût optimal inchangé), et la\n", + "dégradation du coût par l'A* pondéré." ] } ],