diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-5-CompoundMetaheuristics.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-5-CompoundMetaheuristics.ipynb index 6dd3159c96..bac222a07a 100644 --- a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-5-CompoundMetaheuristics.ipynb +++ b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-5-CompoundMetaheuristics.ipynb @@ -1908,7 +1908,7 @@ "- [MGS-6 Benchmarks](MGS-6-Benchmarks.ipynb) — comparatif empirique des composés sur 10 fonctions\n", "- [Point d'entrée Part 4](README.md) — positionnement MGS vs GeneticSharp/mealpy\n", "- [Fork jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — code source, `MetaHeuristicsService.cs`, classes composées (`WhaleOptimisationAlgorithm`, `EquilibriumOptimizer`, `ForensicBasedInvestigation`)\n", - "- [MGS-22 — MGS vs mealpy](MGS-22-MGS-vs-Mealpy.ipynb) : la confrontation lib-vs-lib, PSO canonique compris.\n" + "- [MGS-22 — MGS vs mealpy](MGS-vs-mealpy/MGS-22-MGS-vs-Mealpy.ipynb) : la confrontation lib-vs-lib, PSO canonique compris.\n" ] } ], @@ -1942,4 +1942,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-22-MGS-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-22-MGS-vs-Mealpy.ipynb similarity index 99% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-22-MGS-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-22-MGS-vs-Mealpy.ipynb index 94d55110f3..552fe11161 100644 --- a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-22-MGS-vs-Mealpy.ipynb +++ b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-22-MGS-vs-Mealpy.ipynb @@ -7,7 +7,7 @@ "source": [ "# MGS-22 : MGS contre mealpy — le bench croisé lib-vs-lib sur le Sudoku\n", "\n", - "[Jusqu'ici](MGS-6-Benchmarks.ipynb), les bancs de la série comparaient des **composés entre eux** — WOA contre EO contre Islands, tous construits dans le même moteur. Et quand [Sudoku-05](../../Sudoku/Sudoku-05-PSO-Csharp.ipynb) confrontait le solveur maison à GeneticSharp puis à MetaGeneticSharp (Tranches 2-3), chaque moteur tournait *dans son langage*, avec sa propre fonction de coût et son propre budget — la comparaison était honnête en qualité, approximative en méthode.\n", + "[Jusqu'ici](../MGS-6-Benchmarks.ipynb), les bancs de la série comparaient des **composés entre eux** — WOA contre EO contre Islands, tous construits dans le même moteur. Et quand [Sudoku-05](../../../Sudoku/Sudoku-05-PSO-Csharp.ipynb) confrontait le solveur maison à GeneticSharp puis à MetaGeneticSharp (Tranches 2-3), chaque moteur tournait *dans son langage*, avec sa propre fonction de coût et son propre budget — la comparaison était honnête en qualité, approximative en méthode.\n", "\n", "Ce notebook fait le banc que l'axe 4 de l'issue #11977 demande : **la même expérience, deux bibliothèques, deux langages, dans une seule exécution** — [MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) (C#/.NET 9, DLLs du sous-module) contre [mealpy](https://github.com/thieu1995/mealpy) 3.0.2 (Python/NumPy, la référence du catalogue open-source des métaheuristiques) — reliés par le pont PythonNet dans le kernel .NET. L'hypothèse de départ est celle du user, citée telle quelle : *« possible que les perfs ne suivent pas mealpy sous NumPy optimisé, mais la comparaison sera intéressante »*. Un résultat « MGS plus lent » est donc un livrable valide — à condition qu'il soit **mesuré avec la méthode** : mêmes grilles, mêmes budgets d'évaluations, graines nommées." ] @@ -1099,4 +1099,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-23-DifferentialEvolution-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-23-DifferentialEvolution-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-23-DifferentialEvolution-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-23-DifferentialEvolution-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-25-WhaleOptimisation-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-25-WhaleOptimisation-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-25-WhaleOptimisation-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-25-WhaleOptimisation-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-28-BareBonesPSO-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-28-BareBonesPSO-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-29-GA-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-29-GA-vs-Mealpy.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-29-GA-vs-Mealpy.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-29-GA-vs-Mealpy.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-30-ScatterSearch-Decomposition.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-30-ScatterSearch-Decomposition.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-30-ScatterSearch-Decomposition.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-30-ScatterSearch-Decomposition.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-31-Synthese-Croisee.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-31-Synthese-Croisee.ipynb similarity index 100% rename from MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-31-Synthese-Croisee.ipynb rename to MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-31-Synthese-Croisee.ipynb diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/README.md b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/README.md new file mode 100644 index 0000000000..3cd94b9edb --- /dev/null +++ b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/README.md @@ -0,0 +1,108 @@ +# MGS vs mealpy — campagne comparative + +[↑ Partie 4 : Metaheuristiques composables](../README.md) | [← MGS-21 (représentation vs algorithme)](../MGS-21-Representation-vs-Algorithme.ipynb) + +Cette sous-série regroupe les **dix notebooks comparatifs** de l'Epic « MGS face à mealpy » : un même protocole apparié (même grille, même budget, mêmes graines, déterminisme vérifié), deux bibliothèques comparées (la nôtre en C# .NET 9 contre la référence Python/NumPy), un verdict quantitatif. La campagne n'est pas un benchmark exploratoire — c'est une **décomposition systématique** d'une bibliothèque à l'autre, paire par paire, qui sépare les deux axes que la performance brute mêle (coût d'évaluation vs qualité de solution) et isole l'origine des écarts (moteur vs stratégie). + +## Question directrice + +À budget d'évaluations égal et problème fixé, **quels écarts la bibliothèque C# (MetaGeneticSharp) présente-t-elle face à mealpy 3.0.2 ?** Ces écarts sont-ils **systématiques** (le coût d'évaluation) ou **spécifiques** (la qualité de la solution, signe et ampleur variables) ? Et ces écarts viennent-ils du **moteur** (formules, opérateurs) ou de la **stratégie** (sélection, réinsertion, exploration vs exploitation) ? + +La réponse, étalée sur les neuf paires, distingue deux axes : + +- **Coût systématique** — mealpy est **plus cher par évaluation** sur 8/9 paires (médiane 2,38×, jusqu'à 7,86×), l'unique inversion P1 étant documentée comme un artefact d'instrumentation (écart runtime/noyau, pas algorithme). Le fork C# est systématiquement plus rapide par évaluation, mais cet écart est en partie **absorbé** par la mécanique du moteur (coût Python vs coût C#, fitness-isolée 5-7× plus rapide en C#). +- **Qualité spécifique** — mealpy gagne **6/9 paires**, MGS **3/9**, médianes de −6,5 à +17 conflits. La **direction de l'écart de qualité dépend de la paire** : mealpy écrase en PSO (séparation totale) et EO (étendues disjointes, plus grand écart qualité de l'Epic) ; MGS gagne en SA (premier doublé de l'Epic : qualité et vitesse) et FBI (séparation totale, record de vitesse). + +La question « quel moteur choisir ? » est ainsi **déplacée** : le coût d'évaluation est une donnée d'ingénierie (runtime, GPU, contraintes de latence), mais la qualité dépend du paysage de fitness et de la stratégie de recherche — pas du langage ni de l'écosystème. + +## Protocole commun + +Toutes les paires partagent un **protocole apparié strict** (hérité de MGS-22 et tenu jusqu'à MGS-31) : + +- **Grille** : `Easy[0]` de Sudoku_Easy51 (36 vides), sauf mention contraire dans le notebook. +- **Représentation** : R1 — vecteur continu $[1,10)^{36}$ décodé par arrondi+clamp (cf. MGS-21 pour l'analyse de cette représentation). +- **Budget** : ~8 000 évaluations par course (instrumenté, exactement mesuré dans chaque notebook). +- **Fonction de coût** : conflits lignes + colonnes + blocs. +- **Graines** : `{0, 1, 7, 42}` (4 graines minimum, déterminisme 8/8 ou 12/12 vérifié in-notebook). +- **Sanity check coût** : trois témoins LCG (C# = Python sur des tirages identiques), protégeant contre les biais d'instrumentation. +- **Contre-vérification croisée** : le vainqueur dans une langue est relancé dans l'autre (vérification que le verdict n'est pas un artefact d'un port défectueux). +- **Fitness isolée** : mesure du coût de la fonction de fitness seule (sans la mécanique moteur), pour distinguer l'écart langage de l'écart algorithme. + +Ce protocole est **ferme** : tout écart au protocole est déclaré explicitement dans le notebook (ex. MGS-27 ajuste la génération pour neutraliser les confonds MGS pop×gén vs mealpy pop×epoch ; MGS-26 ajuste l'epoch mealpy à 156 pour le centroïde coûté en 51e évaluation). + +## Table des paires + +| # | Notebook | Paire | Verdict qualité | Verdict vitesse | Fitness isolée C# | +|---|----------|-------|----------------|----------------|-------------------| +| 1 | [MGS-22](MGS-22-MGS-vs-Mealpy.ipynb) | PSO MGS vs OriginalPSO mealpy | mealpy devant (séparation totale 28,5 [26-31] vs 43,5 [39-48]) | ex æquo (0,99×) | 5,72× | +| 2 | [MGS-23](MGS-23-DifferentialEvolution-vs-Mealpy.ipynb) | DE MGS vs OriginalDE mealpy | mealpy devant mais resserré (21,5 vs 25,5, étendues chevauchées, MGS gagne la graine 0) | **MGS 3,45× moins cher** | 6,70× | +| 3 | [MGS-24](MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb) | SA MGS (population-based) vs OriginalSA mealpy (marcheur) | **MGS devant** (27,0 vs 31,0) — premier doublé qualité + vitesse | MGS 3,04× moins cher | 4,20× | +| 4 | [MGS-25](MGS-25-WhaleOptimisation-vs-Mealpy.ipynb) | WOA MGS vs OriginalWOA mealpy + jumeau MGS-Naive | ex æquo MGS-MGS (49,5 = 49,5), mealpy derrière (51,0) | MGS 1,69× moins cher | 3,49× | +| 5 | [MGS-26](MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb) | EO MGS vs OriginalEO mealpy | **mealpy écrase** (25,0 vs 42,0, étendues disjointes) — plus grand écart qualité de l'Epic | MGS 1,21× (plus faible de l'Epic) | 7,75× | +| 6 | [MGS-27](MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb) | FBI MGS vs OriginalFBIO mealpy | **MGS devant** (séparation totale 37,0 vs 43,5) — deuxième doublé | **MGS 4,11× moins cher** (record de l'Epic) | 6,36× | +| 7 | [MGS-28](MGS-28-BareBonesPSO-vs-Mealpy.ipynb) | BBPSO MGS vs jumeau mealpy construit (Kennedy 2003 strict) | mealpy devant à sémantique alignée (25,5 vs 30,5) | MGS 0,50× (2× moins cher) | 4,59× | +| 8 | [MGS-29](MGS-29-GA-vs-Mealpy.ipynb) | Default GA MGS vs BaseGA mealpy | qualité comparable (12,5 vs 13,5, étendues chevauchées — l'écart PSO ne se reproduit pas) | MGS 6,12× moins cher (record) | n/a (sanity check coût IDENTIQUE post #13396) | +| 9 | [MGS-30](MGS-30-ScatterSearch-Decomposition.ipynb) | SS MGS vs jumeau mealpy construit (213 optimisateurs scannés, zéro SS) | **jumeau mealpy gagne** (51,5 vs 54,0, la plus resserrée de l'Epic) | mealpy 0,92× (première défaite vitesse MGS sur le bras complet) | 5,25× | + +**Tableau récapitulatif** (synthèse croisée 9 paires) : [MGS-31](MGS-31-Synthese-Croisee.ipynb). + +## Ordre de lecture + +L'arc n'est **pas** un benchmark exploratoire : chaque notebook ferme un verdict et ouvre une hypothèse pour le suivant. + +1. **Pose du protocole** — [MGS-22](MGS-22-MGS-vs-Mealpy.ipynb) (PSO). Premier duel, séparation totale en qualité, ex æquo en vitesse. La fitness-isolée C# 5,72× est engloutie par la mécanique moteur (~1,8× plus coûteuse côté C#). Hypothèse ouverte : l'écart qualité vient-il du moteur ou de la stratégie de réinsertion ? + +2. **L'écart se resserre-t-il ?** — [MGS-23](MGS-23-DifferentialEvolution-vs-Mealpy.ipynb) (DE). Oui : étendues chevauchées, MGS gagne la graine 0, écart vitesse inversé. Hypothèse ouverte : la stratégie de réinsertion population-side est-elle plus importante que le moteur ? + +3. **Premier doublé** — [MGS-24](MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb) (SA, recuit population-based vs marcheur). MGS gagne qualité ET vitesse. Hypothèse ouverte : la divergence d'architecture (population-based vs single-solution) creuse-t-elle l'écart ? + +4. **Paire canonique** — [MGS-25](MGS-25-WhaleOptimisation-vs-Mealpy.ipynb) (WOA). Trois colonnes, jumeau MGS-Naive comme ablation. Verdict : ex æquo MGS-MGS, mealpy derrière — l'opérateur spiral ne paie pas sur cette géométrie. + +5. **Paire symétrique** — [MGS-26](MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb) (EO). mealpy écrase avec étendues disjointes. Hypothèse ouverte : la sélection greedy par individu (mealpy) bat-elle la réinsertion de population (MGS) ? + +6. **Paire miroir** — [MGS-27](MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb) (FBI, port MGS revendiqué depuis mealpy). Les équations ont dérivé (bruit A1 N(0,1) vs uniforme). MGS gagne les deux mains. Hypothèse ouverte : la dérive de bruit est-elle l'origine de l'écart ? + +7. **Décomposition de l'écart d'ancrage** — [MGS-28](MGS-28-BareBonesPSO-vs-Mealpy.ipynb) (BBPSO, Kennedy 2003 strict). Trois bras isolent ancrage (nul) et noyau (réel : mealpy devant). Hypothèse : le coût d'évaluation importe-t-il plus que la sémantique ? + +8. **Revanche du GA** — [MGS-29](MGS-29-GA-vs-Mealpy.ipynb) (GA, après correction #13396 du décalage d'index de colonne). L'écart PSO ne se reproduit pas GA contre GA. Hypothèse : la sémantique moteur (composants) domine-t-elle la sémantique stratégie (réinsertion) ? + +9. **Paire sans équivalent mealpy** — [MGS-30](MGS-30-ScatterSearch-Decomposition.ipynb) (Scatter Search, construit en jumeau par subclass). Le jumeau mealpy gagne les deux mains. Hypothèse : la diversité de RefSet (b2) porte-t-elle le bénéfice ? + +10. **Synthèse croisée** — [MGS-31](MGS-31-Synthese-Croisee.ipynb). Récolte des médianes/étendues/coûts depuis les seuls outputs committés (zéro re-run, intégrité re-dérivée 9/9), tableau croisé qualité × coût, deux graphiques SVG, deux lectures d'isolation (P7 jumeaux mealpy à formules distinctes → noyau ; P9 ablation SS → stratégie). + +## Distinction benchmark diagnostique / amélioration MGS + +Cette sous-série est **explicitement diagnostique**, pas prescriptive. Aucune des neuf paires ne conclut « il faut remplacer X par Y dans MGS » ; aucune n'ouvre une branche d'amélioration MGS. La boucle benchmark → diagnostic → correctif → re-benchmark est suivie **séparément** (cf. issue #13778 : « MGS vs mealpy : convertir les benchmarks en correctifs MGS puis re-mesurer »). + +Ce qui est livré ici, c'est la **photographie mesurée** d'un instant — fork C# à commit `501beeac7` × mealpy 3.0.2 — avec : + +- les écarts reproductibles (sanity check coût, déterminisme 8/8 ou 12/12) ; +- les sources identifiées (sélection greedy vs réinsertion population, bruit N(0,1) vs uniforme, opérateurs de sélection/recuit) ; +- les impasses déclarées (l'écart qualité PSO ne se reproduit pas GA — ce n'est pas un signal unidirectionnel). + +**Ce qui n'est PAS livré** : une prescription d'amélioration, un re-benchmark après correction, un classement final des deux bibliothèques. La campagne laisse les **questions ouvertes** documentées et reproductibles ; les réponses sont une autre campagne. + +## Configuration requise + +Identique à la série parente ([Partie 4 README §Configuration requise](../README.md#configuration-requise)) : + +- Kernel `dotnet-interactive` 1.0.707101+ (hôte .NET moderne, charge net8.0/net9.0/net10). +- Sous-module `MetaGeneticSharp/` buildé (DLLs `net9.0`). +- Pont PythonNet pour les comparaisons mealpy (kernel `.NET` charge `mealpy` 3.0.2 via Python.NET). +- Reproductibilité seedée pour MGS-22 à MGS-31 (graines `{0, 1, 7, 42}` + `FastRandomRandomization.ResetSeed`). + +Règle C.2 : notebooks committés **avec leurs outputs** (exécution réelle, kernel .NET). + +## Conventions + +- **Repères entre paires** : chaque notebook déclare ses confonds paramétriques neutralisés et ses écarts au protocole commun. Une lecture transverse requiert MGS-31 (synthèse), pas une moyenne des neuf verdicts isolés. +- **Pas de préférence affichée** : les verdict « MGS devant » / « mealpy devant » / « ex æquo » / « comparable » sont publiés tels quels, sans tri de présentations. L'Epic ne « gagne » ni ne « perd » : elle mesure. +- **Limites disclosed** : checkpoints 2/9 (sept paires perdent les checkpoints intermédiaires), un seul paysage (Sudoku-Easy[0]), un seul budget (8 000 évals), 4 graines, un seul fork à un instant donné. + +## Liens + +- [Série parente — Partie 4 : Metaheuristiques composables](../README.md) — vue d'ensemble de la thèse « composants > métaphores » et du side-track C#/.NET 9 +- [Fork jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — code source, tests unitaires, ROADMAP +- [Issue #13777 — MGS vs mealpy : isoler les face-à-face dans une sous-série dédiée](https://github.com/jsboige/CoursIA/issues/13777) — fondatrice de cette sous-série +- [Issue #13778 — MGS vs mealpy : convertir les benchmarks en correctifs MGS puis re-mesurer](https://github.com/jsboige/CoursIA/issues/13778) — campagne d'amélioration (séparée, non livrée ici) +- [Search-11-Métaheuristiques](../../Part1-Foundations/Search-11-Metaheuristics.ipynb) — introduction Python (PSO, ABC, SA, BRO via mealpy, benchmark comparatif) diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/README.md b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/README.md index c4767830d2..faedf5b360 100644 --- a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/README.md +++ b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/README.md @@ -1,354 +1,345 @@ -# Partie 4 : Metaheuristiques Composables (MetaGeneticSharp) - -[↑ Série Search](../README.md) | [← Partie 3 : Recherche avancée](../Part3-Advanced/README.md) | [Notebooks MGS →](MGS-1-Introduction.ipynb) - -Comment passer de l'application *d'une* métaheuristique à la **composition** de plusieurs ? Cette partie ouvre la voie à [MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — une bibliothèque .NET qui reconstruit les métaheuristiques publiées (Whale Optimization, Equilibrium Optimizer, Differential Evolution, Bare-Bones PSO, modèle insulaire...) à partir de **primitives réutilisables** plutôt que comme des monolithes opaques. Trente-cinq notebooks .NET Interactive (C#) en sont le fil conducteur : un algorithme doit pouvoir s'énoncer en quelques lignes déclaratives, et chaque brique (sélection, croisement, mutation, réinsertion) doit pouvoir être interceptée et recomposée. - -L'arc part de la grammaire fluente (composition, MGS-1..5), caractérise les biais de l'optimiseur (centrage MGS-10, rotation MGS-12, synergie d'îles MGS-11/14), puis culmine sur le **No-Free-Lunch** : quatre capstones réunissent ses réponses classiques — mesurer le paysage (MGS-15), sélectionner l'algorithme (MGS-16), contrôler le paramètre pendant la course (MGS-17), éprouver le tout sur le banc CEC standard shift+rotate combiné (MGS-18) — avant un **démontage** : MGS-19 débranche l'opérateur de recuit du compound SA et l'éprouve isolé, montrant qu'un composant *fonctionne* détaché mais ne porte pas seul le bénéfice du tout ; puis une **inversion de la question** : MGS-21 croise représentation × algorithme sur le Sudoku et mesure que le choix de l'espace de recherche peut peser plus que le choix du moteur ; enfin une **confrontation externe** : MGS-22 oppose la bibliothèque à mealpy (Python/NumPy) sur un protocole apparié dans une seule exécution kernel .NET — ex æquo en vitesse, mealpy devant en qualité à paramètres par défaut, et la fitness C# 5,72× plus rapide engloutie par la mécanique moteur — puis MGS-23 rejoue la paire sur Differential Evolution : l'écart qualité se resserre (étendues chevauchées, MGS gagne une graine) et la vitesse s'inverse (MGS 3,45× moins cher par évaluation) ; enfin MGS-24 oppose les deux recuits simulés — paire structurellement divergente (recuit géométrique population-based contre marcheur single-solution à pas gaussien) et **premier doublé de l'Epic** : MGS domine qualité (27,0 contre 31,0 conflits médians) et vitesse par évaluation (3,04×) ; MGS-25 referme la série ouverte avec la paire la plus canonique — WOA de part et d'autre en Mirjalili 2016 strict, zéro confond paramétrique, trois colonnes (spirale MGS, naive convexe, mealpy) : ex æquo MGS-MGS (49,5), mealpy derrière (51,0) et 1,69× plus cher, avec la contre-mesure directe de MGS-19 — l'opérateur spiral ne paie pas ici. MGS-26 retourne la paire la plus symétrique contre le port : Equilibrium Optimizer de part et d'autre en Faramarzi et al. strict (mêmes équations, mêmes constantes, même pool — zéro confond), et mealpy écrase — 25,0 contre 42,0 conflits médians, étendues disjointes (le pire mealpy à neuf unités du meilleur MGS), le plus grand écart qualité de l'Epic — un écart qui ne peut venir que de la traduction (sélection greedy par individu contre réinsertion de population, centroïde coûté en 51e évaluation côté mealpy), MGS ne gardant la main que de peu en vitesse (1,21×, son plus faible avantage de l'Epic) ; MGS-27 referme la question sur la paire qui prétendait le moins à la différence : le FBI MGS est un portage revendiqué **depuis mealpy même**, mais ses équations ont dérivé (bruit A1 normal contre uniforme) — et le port dérivé bat sa référence des deux mains : séparation totale de qualité (37,0 contre 43,5, le meilleur mealpy sous le pire MGS) et 4,11× moins cher par évaluation, le plus grand écart de vitesse de l'Epic. MGS-28 referme le volet PSO avec la paire la plus dépouillée — Bare-Bones PSO (Kennedy 2003), zéro coefficient w/c1/c2, la particule tirée en bloc autour du milieu ancre-gbest : décomposition en trois bras qui isole l'ancre (pbest contre position courante) du moteur, et le verdict est chirurgical — écart d'ancrage **nul** (jumeaux mealpy identiques graine par graine), tout l'écart est noyau : mealpy devant à sémantique alignée (25,5 contre 30,5 conflits médians) quand MGS rend son avance de vitesse (2× moins cher par évaluation). MGS-29 rejoue la confrontation sur le GA : après la correction #13396 du décalage d'index de colonne de l'unité bloc (le sanity check coût était DIFFERENT — C# 67/71/60 contre Python 100/105/96 — et le notebook le déclarait lui-même invalide), il est désormais IDENTIQUE et le verdict se rejoue sous le vrai paysage — **qualité comparable** (mealpy 12,5 [9-16] contre MGS 13,5 [12-18], étendues chevauchées : l'écart PSO de MGS-22 ne se reproduit pas GA contre GA) tandis que MGS reste 6,12× moins cher par évaluation. MGS-30 referme l'Epic sur la paire sans équivalent mealpy : Scatter Search n'existe pas dans le paquet (213 optimisateurs scannés, zéro occurrence — preuve mesurée in-notebook), le jumeau est donc **construit** comme subclass pinnant le template Glover ; et le banc croisé à trois bras renverse le scénario — le jumeau mealpy gagne la qualité (51,5 [48-53] contre 54,0 [43-56], la plus resserrée des étendues de l'Epic) **et** la vitesse par évaluation contre le composé complet (0,92×, la diversité max-min C# non vectorisée coûte 4,7× l'élitisme pur), tandis que l'ablation qf=1,0 montre l'axe diversité b2 **signe-ambivalent par graine et défavorable en médiane** (52,0 contre 54,0) — verdict sans appel pour ce problème : sans sa couche mémétique différée, le Scatter Search est le moteur le plus faible de l'Epic, et sa diversité de RefSet ne le sauve pas à ce budget. MGS-31 referme l'Epic par la **synthèse croisée** des neuf paires : le notebook récolte les médianes/étendues/coûts depuis les seuls outputs committés (zéro re-run, intégrité re-dérivée 9/9), et le tableau croisé sépare les deux axes que chaque paire mêlait — l'écart de **coût est systématique** (mealpy plus cher par évaluation sur 8/9 paires, médiane 2,38x, jusqu'à 7,86x en P8, l'unique inversion P1 étant un artefact d'instrumentation documenté : un écart de runtime/noyau, pas d'algorithme), l'écart de **qualité est spécifique** (mealpy devant 6/9, MGS 3/9, de −6,5 à +17 conflits médians) — et les bras de décomposition tranchent l'origine : P7 (formules équivalentes, écarts conservés) isole le moteur, P9 (ablation du mécanisme interne) isole la stratégie. - -Et cette composition se *voit* : avant de choisir un algorithme, MGS-8 rend le paysage de fitness en vraie heatmap graphique — chaque pixel coloré selon sa valeur de fitness, l'optimum global marqué en clair. - -[![Paysage de fitness analytique : heatmap de la fonction Sphere, l'optimum global au centre](assets/readme/mgs8-landscape.png)](MGS-8-LandscapeExplorer.ipynb) - -Contrairement aux Parties 1 et 2 (notebooks Python avec OR-Tools, DEAP, mealpy), cette partie est un **side track C# .NET 9.0** : elle consomme GeneticSharp et la couche métaheuristique comme sous-modules, et s'exécute via le kernel `dotnet-interactive`. C'est le pont entre la série pédagogique Python et une vraie bibliothèque de code industrialisable — la démonstration que les concepts vus en Python (Search-5 génétique, Search-11 métaheuristiques) se retrouvent, solidement typés et composables, dans un runtime .NET. Les notebooks consomment la bibliothèque (sous-module voisin [`MetaGeneticSharp/`](../MetaGeneticSharp/)) via ses DLLs buildées. - -## Pourquoi cette partie - -Les Parties 1-2 enseignent à *choisir* une métaheuristique face à un problème ; cette partie enseigne à en *construire* et en *combiner*. La motivation est double : - -- **Pédagogique.** Reconstruire WOA ou EO à partir de primitives (`Match`, `Container`, `Scoped`, contrôle-flux géométrique) force à comprendre *pourquoi* chaque étape existe — là où importer `mealpy` ou `scipy` masque le mécanisme derrière un appel de fonction. C'est le même réflexe qu'écrire un A* à la main avant d'utiliser `networkx`. -- **Ingénierie.** La composition ouvre des configurations qu'aucune bibliothèque monolithique n'offre directement : sous-populations spécialisées (Eukaryote), migration entre îles (Islands), métaheuristiques hybrides assemblées par grammaire fluente. Ces patterns existent dans la littérature mais sont rares dans les libs grand public. - -L'enseignement transversal rejoint celui des Parties 1-2 : aucune métaheuristique ne domine partout (cf [Search-11](../Part1-Foundations/Search-11-Metaheuristics.ipynb)), et la bonne réponse à un problème d'optimisation est rarement « l'algorithme X » mais plutôt « la bonne composition de primitives pour ce paysage de fitness ». - -## Positionnement : MetaGeneticSharp dans le paysage - -| Bibliothèque | Langage | Représentation | Philosophie | Lien | -|--------------|---------|----------------|-------------|------| -| **MetaGeneticSharp** | C# .NET 9 | Agnostique (gènes = interfaces GeneticSharp) | **Composants > métaphores** : algorithmes reconstruits depuis des primitives composables | [jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) | -| GeneticSharp | C# .NET | Agnostique (bit, permutation, arbre, float) | Bibliothèque GA classique, opérateurs en interfaces | [giacomelli/GeneticSharp](https://github.com/giacomelli/GeneticSharp) (sous-module, v3.1.4-9 / upstream master 4406ad7, non patché) | -| mealpy | Python | Vecteurs (continus surtout) | Catalogue large, tronc commun vectoriel, très compact | [thieu1995/mealpy](https://github.com/thieu1995/mealpy) | -| HeuristicLab | C# .NET | Plugin-based, GUI lourde | Plateforme d'expérimentation, optimisation interactive | [heal-research/HeuristicLab](https://github.com/heal-research/HeuristicLab) | - -MetaGeneticSharp vise le point que les autres n'occupent pas : **l'expressivité déclarative de mealpy** (un algorithme en quelques lignes) **sur la représentation agnostique de GeneticSharp** (bit strings, permutations, arbres), sans sacrifier la performance. C'est le « child project » que [GeneticSharp PR #87](https://github.com/giacomelli/GeneticSharp/pull/87) suggérait de devenir : la couche métaheuristiques du PR, absorbée dans un moteur autonome au-dessus d'un GeneticSharp vanilla. - -## Objectifs d'apprentissage - -À l'issue de cette partie, vous serez capable de : - -1. **Reconstruire** une métaheuristique publiée (WOA, EO) à partir de primitives composables plutôt que d'en importer une boîte noire -2. **Composer** des métaheuristiques via la grammaire fluente (`Match`, `Container`, `Scoped`) pour assembler des configurations hybrides -3. **Structurer** une population en sous-populations spécialisées (Eukaryote) ou en îles migratoires (Islands) -4. **Évaluer** quand une composition custom bat une métaheuristique monolithique sur un paysage de fitness donné - -## Notebooks - -Cette partie se compose de trente-cinq notebooks .NET Interactive (C#), hébergés dans ce répertoire et consommant le sous-module voisin [`MetaGeneticSharp/`](../MetaGeneticSharp/) : - -| # | Notebook | Concept clé | Primitives introduites | Durée | -|---|----------|-------------|------------------------|-------| -| 1 | [MGS-1-Introduction](MGS-1-Introduction.ipynb) | Moteur autonome `MetaGeneticAlgorithm` | `DefaultMetaHeuristic`, `NoOp`, fitness quadratique | ~40 min | -| 2 | [MGS-2-Composition](MGS-2-Composition.ipynb) | Assemblage déclaratif | `Match`, contrôle-flux, grammaire fluente | ~45 min | -| 3 | [MGS-3-Eukaryote](MGS-3-Eukaryote.ipynb) | Sous-populations spécialisées | chromosomes composites, partitionnement | ~50 min | -| 4 | [MGS-4-Islands](MGS-4-Islands.ipynb) | Modèle insulaire | populations structurées, migration entre îles | ~50 min | -| 5 | [MGS-5-CompoundMetaheuristics](MGS-5-CompoundMetaheuristics.ipynb) | Reconstruire les composés publiés (WOA/EO/FBI) | `MetaHeuristicsService`, `WhaleOptimisationAlgorithm`, `EquilibriumOptimizer`, factory `CreateMetaHeuristicByName` | ~50 min | -| 6 | [MGS-6-Benchmarks](MGS-6-Benchmarks.ipynb) | Comparaison honnête | `KnownFunctions`, composé WOA vs Uniform vs Islands | ~50 min | -| 7 | [MGS-7-TSP](MGS-7-TSP.ipynb) | Grammaire agnostique à la représentation | `TspFitness`, `OrderedCrossover`, permutation + `Islands` | ~45 min | -| 7b | [MGS-7b-LandscapeMultidim](MGS-7b-LandscapeMultidim.ipynb) | Projection N-D des paysages (voir en dimension ≥ 5) | surcharge `RenderHeatmap` N-D de `KnownFunctionLandscape`, projection MAX sur les coordonnées cachées (opérateur Gtk# verbatim) ; Sphere 2-D vs 5-D, Rastrigin n=2/5/10/30, Schwefel n=5/30 | ~30 min | -| 7c | [MGS-7c-RosenbrockGriewank](MGS-7c-RosenbrockGriewank.ipynb) | Projection N-D : Rosenbrock (vallée banane) + Griewank (produit-cosinus) | `RosenbrockFitness`, `GriewankFitness` sur la surcharge N-D de `RenderHeatmap` ; dims $n=2/5/30$ ; la vallée étroite de Rosenbrock (largeur $\sim 10^{-2}$) disparaît en MAX-projection 30-D, Griewank produit-cosinus $\prod \cos(x_i/\sqrt{i})$ vs Ackley somme-cosinus | ~30 min | -| 7d | [MGS-7d-MichalewiczDixonPrice](MGS-7d-MichalewiczDixonPrice.ipynb) | Projection N-D : Michalewicz (crêtes raides) + Dixon-Price (vallée non-scalable) | `MichalewiczFitness` (paramètre $m=10$), `DixonPriceFitness` sur la surcharge N-D de `RenderHeatmap` ; dims $n=2/5/30$ ; crêtes quasi-binaires de Michalewicz ($m=10$ sature l'amplitude), vallée parabolique-croisée non-rectiligne de Dixon-Price | ~30 min | -| 8 | [MGS-8-LandscapeExplorer](MGS-8-LandscapeExplorer.ipynb) | Visualiser la surface de fitness | heatmaps PNG graphiques, 3 modes (fonction / carte d'altitude / image), trajectoire de convergence | ~50 min | -| 9 | [MGS-9-EverestRelief](MGS-9-EverestRelief.ipynb) | Relief terrestre réel comme paysage | `DemGrid` (wrapper `ImageHeightMapFunction`), cartes `KnownHeightMap` de jsboige, GA/WOA/EO vs PSO, flipbook de convergence | ~55 min | -| 10 | [MGS-10-CenterBias](MGS-10-CenterBias.ipynb) | Biais central vs robustesse au déplacement | banc `CenterBiasBenchmark` (Kudela 2022), composés WOA/EO/FBI/DE/BBPSO/SA vs GA/Random, signature $\Delta$ | ~45 min | -| 11 | [MGS-11-IslandSynergy](MGS-11-IslandSynergy.ipynb) | Synergie d'îles complémentaires (verdict mesuré) | `IslandCompoundMetaheuristic`, archipel hétérogène DE+BBPSO, dé-biais `ShiftedFitness`, GIF multicolore par île | ~45 min | -| 12 | [MGS-12-AxisAlignment](MGS-12-AxisAlignment.ipynb) | Biais d'alignement d'axes (rotation) | décorateur `RotatedFitness` ($M x$, Givens orthogonale), séparabilité vs rotation, optimum relocalisé, signature $\Delta$ | ~45 min | -| 13 | [MGS-13-LandscapeDebias](MGS-13-LandscapeDebias.ipynb) | Pourquoi la rotation casse la séparabilité (visuel) | heatmaps 2-D des fonctions dé-biaisées `ShiftedFitness`/`RotatedFitness`, Sphere invariante vs Rosenbrock/Rastrigin rotatées, composition CEC | ~40 min | -| 14 | [MGS-14-IslandSynergyFound](MGS-14-IslandSynergyFound.ipynb) | Une synergie d'îles *trouvée* (et un cas négatif) | archipel `DE+BB-3:1` (3 îles DE + 1 île BBPSO), migration douce, banc multi-seed à contrôle propre, synergie robuste sur Ackley / absente sur Rastrigin | ~45 min | -| 15 | [MGS-15-LandscapeAnalysis](MGS-15-LandscapeAnalysis.ipynb) | Le *nombre* derrière la heatmap — FDC globale + rugosité locale | deux métriques complémentaires : FDC (Jones & Forrest 1995, Pearson fitness–distance, nuage SVG inline) + autocorrélation de marche aléatoire (Weinberger 1990, longueur de corrélation) + neutralité ; Sphere FDC 0,97 & lisse vs Rastrigin FDC 0,71 & rugueux (L≈1 pas) | ~40 min | -| 16 | [MGS-16-AlgorithmSelection](MGS-16-AlgorithmSelection.ipynb) | **Capstone** — sélectionner le bon optimiseur selon le paysage (Rice 1976) | No-Free-Lunch (Wolpert & Macready 1997) + cadre de Rice (features → portfolio → performance) ; réutilise les 8 optimiseurs de MGS-10 et les features FDC/ρ₁/neutralité de MGS-15 ; sélecteur heuristique validé puis testé sur un 4ᵉ paysage inconnu (Rosenbrock) | ~70 min | -| 17 | [MGS-17-ParameterControl](MGS-17-ParameterControl.ipynb) | **Deuxième réponse au No-Free-Lunch** — adapter les paramètres pendant la course (Eiben 1999) | taxonomie Eiben (tuning vs control : déterministe / adaptatif / self-adaptatif) via le vrai moteur du fork `ProbabilityConfig.DynamicProbability` ; schedule de décroissance, contrôle adaptatif par diversité, self-adaptatif hétérogène ; No-Free-Lunch au niveau du *paramètre* (l'ordre s'inverse entre Rastrigin et Sphere) | ~50 min | -| 17b | [MGS-17b-Empirical-Algorithm-Selection](MGS-17b-Empirical-Algorithm-Selection.ipynb) | **Distillation Theodore Deguest L4 EPITA SCIA 2026** — squelette : cadre theorique (Rice 1976, Wolpert 1996, Smith-Miles 2009) + setup env execute | introduction, attribution, plan en 4 tranches (cadre / protocole 3 terrains / Pareto+discriminant / ponts series) ; noyau execute via kernel `coursia-ml-training` ; PR Theodore Deguest [jsboigeEpita/2026-Epita-Intelligence-Symbolique#42](https://github.com/jsboigeEpita/2026-Epita-Intelligence-Symbolique/pull/42) | ~30 min (tranches 1+2+3 livrees ; tranche 4 benchmarks reels Theodore par ai-01 ou lane GPU) | -| 18 | [MGS-18-CecBanc](MGS-18-CecBanc.ipynb) | **Consolidation du banc CEC** — shift+rotate combinés (le protocole standard de dé-biais) | décorateurs composés `RotatedFitness(ShiftedFitness(inner, offset), M)` (Givens orthogonale) ; banc à 4 variantes (plain/shifted/rotated/combined), étend `CenterBiasBenchmark` ; 8 optimiseurs sous shift+rotate sur Ackley+Rosenbrock ; les biais isolés (WOA central MGS-10, GA axe MGS-12) se composent — effet sub-additif ou super-additif selon le paysage | ~50 min | -| 19 | [MGS-19-MetropolisReinsertion](MGS-19-MetropolisReinsertion.ipynb) | **Recuit simulé décomposé** — l'opérateur de Metropolis débranché de SA et greffé seul sur un GA | `MetropolisReinsertion` isolé du compound `SimulatedAnnealing` et injecté via `MetaGeneticAlgorithm.Reinsertion` ; banc 5 configs (pairwise greedy contrôle, 3 températures Metropolis, élitiste référence) sur Sphere/Rastrigin/Ackley + limite frozen ; verdict honnête **négatif** — l'acceptation `exp(Δ/T)` détachée du couplage perturbation+acceptation ne porte pas le bénéfice du recuit | ~45 min | -| 21 | [MGS-21-Representation-vs-Algorithme](MGS-21-Representation-vs-Algorithme.ipynb) | **Représentation × algorithme : le plan croisé Sudoku** — quel facteur pèse le plus ? | deux représentations (R1 vecteur continu + décodage arrondi, R2 grille à permutations de lignes via l'algèbre de swaps) × deux moteurs (PSO composé, GA permutation), budget ~8 000 évaluations, 4 graines {0,1,7,42}, critère de verdict pré-enregistré ; verdict en deux temps — la représentation domine la colonne PSO (−39 conflits vs −34,5/−6 pour l'algorithme), comparable sur la colonne GA ; 4/4 résolutions en R2/GA, aucune en R1 ; cause mesurée : 100 % des candidats R1 décodés tombent hors de l'espace admissible | ~40 min | -| 22 | [MGS-22-MGS-vs-Mealpy](MGS-22-MGS-vs-Mealpy.ipynb) | **Bench croisé MGS vs mealpy** — la même expérience, deux bibliothèques, deux langages, une exécution | protocole apparié (même grille Easy[0], même budget ~8 000 évals instrumenté, graines {0,1,7,42}, coût implémenté deux fois et égalité prouvée) ; PSO MGS (DLLs fork) contre OriginalPSO mealpy 3.0.2 via pont PythonNet dans le kernel .NET ; verdict — qualité : mealpy domine (28,5 [26-31] vs 43,5 [39-48] conflits, séparation totale), vitesse : ex æquo (0,99×, médiane 3 reps après amendement anti-pic GC), fitness isolée : C# 5,72× plus rapide mais engloutie par la mécanique moteur ~1,8× plus coûteuse ; déterminisme 8/8 prouvé in-notebook | ~40 min | -| 23 | [MGS-23-DifferentialEvolution-vs-Mealpy](MGS-23-DifferentialEvolution-vs-Mealpy.ipynb) | **DE croisé MGS vs mealpy** — l'écart du PSO se reproduit-il ? | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré 8 000/8 050 évals, graines {0,1,7,42}, contre-vérif croisée du vainqueur, déterminisme 8/8) ; composé MGS `DifferentialEvolution` (DE/rand/1/bin, F=0,5, CR=0,9) contre `OriginalDE` mealpy 3.0.2 (wf=0,1, cr=0,9 — confond F déclaré et neutralisé à l'exercice 1) ; verdict — qualité : mealpy devant mais **écart resserré** (21,5 [20-27] vs 25,5 [20-29] conflits, étendues chevauchées, MGS gagne la graine 0 — plus de séparation totale comme en PSO), vitesse : **inversée** (MGS 3,45× moins cher par éval, 0,054 vs 0,188 ms — le PSO était ex æquo), fitness isolée : C# 6,70× plus rapide et cette fois l'écart moteur reste sous l'écart fitness | ~40 min | -| 24 | [MGS-24-SimulatedAnnealing-vs-Mealpy](MGS-24-SimulatedAnnealing-vs-Mealpy.ipynb) | **Recuit croisé MGS vs mealpy** — deux architectures du recuit, un seul budget | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré 8 000/8 002 évals — le marcheur mealpy consomme 1 éval/epoch, donc epoch = 8 000, graines {0,1,7,42}, contre-vérif croisée, déterminisme 8/8) ; composé MGS `SimulatedAnnealing` (recuit **géométrique population-based** : T_0=1,0, α=0,95, croisement géométrique, réinsertion Metropolis) contre `OriginalSA` mealpy 3.0.2 (**marcheur single-solution** : temp_init=100, T=temp_init/epoch, pas gaussien step_size=0,1 — divergence d'architecture déclarée d'entrée, confonds paramétriques neutralisés aux exercices 1/3) ; verdict — **premier doublé de l'Epic** : MGS devant en qualité (27,0 [22-28] vs 31,0 [27-34] conflits, chevauchement réduit à la marge) **et** en vitesse (3,04× moins cher par éval, 0,039 vs 0,119 ms), fitness isolée C# 4,20× ; lecture : à budget égal, le recuit porté par une population explore plus largement qu'un marcheur mono-solution | ~40 min | -| 25 | [MGS-25-WhaleOptimisation-vs-Mealpy](MGS-25-WhaleOptimisation-vs-Mealpy.ipynb) | **WOA croisé MGS vs mealpy** — la paire la plus canonique, trois colonnes | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré 8 000/8 050 évals, graines {0,1,7,42}, contre-vérif croisée, déterminisme **12/12** sur 3 moteurs) ; croisement à trois colonnes — MGS `WhaleOptimisation` (Mirjalili 2016 canonique : a 2→0 linéaire, spiral bubble-net), MGS `WhaleOptimisationNaive` (spirale remplacée par combinaison convexe 0,5·X+0,5·X*, la simplification que MGS-19 démontait) et mealpy `OriginalWOA` 3.0.2 (mêmes équations, même schedule — **aucun confond paramétrique**) ; verdict — qualité : **ex æquo MGS-MGS** (49,5 [46-51] et 49,5 [46-53]) avec mealpy derrière (51,0 [50-54], aucune graine gagnée nettement), vitesse : MGS 1,69× moins cher par éval, fitness isolée C# 3,49× ; deux lectures — l'opérateur spiral ne paie pas sur Sudoku-R1 (contre-mesure directe de MGS-19) et le WOA est le pire moteur de l'Epic toutes colonnes confondues (contraction vers le barycentre) | ~40 min | -| 26 | [MGS-26-EquilibriumOptimizer-vs-Mealpy](MGS-26-EquilibriumOptimizer-vs-Mealpy.ipynb) | **EO croisé MGS vs mealpy** — le port face à son original, la paire la plus symétrique | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré 8 000/8 006 évals — l'epoch mealpy ajusté à 156 pour le centroïde coûté en 51e évaluation, graines {0,1,7,42}, contre-vérification croisée, déterminisme 8/8) ; composé MGS `EquilibriumOptimizer` (Eq. 9-16 de Faramarzi et al., constantes codées en dur V=1, a1=2, a2=1, GP=0,5, pool 4 meilleurs + centroïde) contre `OriginalEO` mealpy 3.0.2 (mêmes équations, mêmes constantes — zéro confond paramétrique) ; verdict — **mealpy écrase en qualité avec étendues disjointes** (25,0 [21-31] vs 42,0 [40-46] — le pire mealpy à 9 unités du meilleur MGS, plus grand écart qualité de l'Epic, deuxième victoire mealpy après le PSO mais sans aucun chevauchement) tandis que MGS ne garde la vitesse que de peu (1,21× moins cher par éval, 0,066 vs 0,081 ms — son plus faible avantage de l'Epic), fitness isolée C# 7,75× ; lecture : mêmes mathématiques des deux côtés, l'écart ne peut venir que de la traduction — sélection greedy par individu côté mealpy contre réinsertion de population côté MGS, et centroïde jamais coûté côté MGS (8 000 = 160×50 exactement, 50 + 156×51 côté mealpy) | ~40 min | -| 27 | [MGS-27-ForensicBasedInvestigation-vs-Mealpy](MGS-27-ForensicBasedInvestigation-vs-Mealpy.ipynb) | **FBI croisé MGS vs mealpy** — la paire miroir, et ses deux dérives | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré 7 962-8 172/8 050 évals — MGS pop 50 × 200 générations à ~40 évals/gén contre mealpy pop 50 × 40 epochs à 200 évals/epoch, graines {0,1,7,42}, contre-vérif croisée, déterminisme 8/8) ; composé MGS `ForensicBasedInvestigation` (quatre phases A1/A2/B1/B2, bruit A1 **N(0,1) par Box-Muller**, réinsertion pairwise) contre `OriginalFBIO` mealpy 3.0.2 (mêmes phases, bruit A1 **uniforme (−1,1)** — le port C# revendique une traduction directe de mealpy, mais les équations ont dérivé : aucune paire de l'Epic ne prétendait moins à la différence, et aucune n'expose moins de confonds — zéro paramètre scalaire des deux côtés) ; verdict — **deuxième doublé de l'Epic, le plus net** : MGS devant en qualité avec **séparation totale** (37,0 [25-39] vs 43,5 [43-45] — le meilleur mealpy sous le pire MGS, 4/4 graines) **et** en vitesse (4,11× moins cher par éval, 0,031 vs 0,127 ms — record de l'Epic), fitness isolée C# 6,36× ; lecture : le bruit A1 à queues lourdes du port explore plus amplement (hypothèse déclarée), cohérente avec la variance MGS [25-39] contre la régularité mealpy [43-45] | ~40 min | -| 28 | [MGS-28-BareBonesPSO-vs-Mealpy](MGS-28-BareBonesPSO-vs-Mealpy.ipynb) | **BBPSO croisé MGS vs mealpy** — Kennedy 2003, l'écart d'ancrage nul | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré 8 000/8 050 évals, graines {0,1,7,42}, contre-vérif croisée, déterminisme **12/12** sur 3 moteurs) ; décomposition **trois bras** — composé MGS `BareBonesParticleSwarm` (ancre = position courante, réinsertion gloutonne best-N), jumeau mealpy 3.0.2 par subclass `Optimizer` (point d'extension natif, aucun des 7 PSO du catalogue n'étant bare-bones — catalogue imprimé in-notebook) en deux variantes : mealpy-mgs à sémantique alignée (exacte formule MGS) et mealpy-kennedy littéral 2003 (ancre = pbest, remplacement inconditionnel) ; la cellule formules AVANT mesure tranche les deux divergences documentées et vérifie le gel (std=0 ⇒ tirage déterministe) ; verdict — **écart d'ancrage nul** : les deux jumeaux mealpy produisent des trajectoires identiques graine par graine (médianes 25,5 = 25,5, écarts de checkpoints [0,0,0,0] sur 4/4 graines) ; **écart noyau réel** : mealpy devant à sémantique alignée (25,5 [19-27] vs 30,5 [29-31] — forme en croisement, MGS devant au premier quart puis gelé dès cp25 sur 3/4 graines, mealpy exploitant jusqu'au bout), vitesse : MGS 0,50× (2× moins cher par éval, 0,036 vs 0,073 ms), fitness isolée C# 4,59× | ~40 min | -| 29 | [MGS-29-GA-vs-Mealpy](MGS-29-GA-vs-Mealpy.ipynb) | **GA croisé MGS vs mealpy** — la revanche du GA | protocole apparié hérité de MGS-22 (grille Easy[0] R1, budget mesuré ~8 050 évals, graines {0,1,7,42}, déterminisme 8/8) ; composé MGS `Default` contre `BaseGA` mealpy 3.0.2 ; sanity check coût **IDENTIQUE** (3 témoins LCG — C# 67/71/60 = Python 67/71/60) et contre-vérif croisée **IDENTIQUE** (16=16), après correction #13396 du décalage d'index de colonne de l'unité bloc (`j // 3` → `j % 3`) ; verdict — **qualité comparable** (mealpy 12,5 [9-16] vs MGS 13,5 [12-18], médianes proches, étendues chevauchées — le critère pré-enregistré exige médiane stricte ET max < min : non vérifié) et **MGS devant en vitesse** (6,12× moins cher par évaluation) ; la correction #13396 replace la paire : l'écart qualité du PSO (MGS-22) ne se reproduit pas GA contre GA | ~35 min | -| 30 | [MGS-30-ScatterSearch-Decomposition](MGS-30-ScatterSearch-Decomposition.ipynb) | **Scatter Search en décomposition 3 bras** — la paire sans équivalent mealpy, refermée sur l'axe interne du moteur | preuve d'absence mesurée in-notebook (213 optimisateurs mealpy 3.0.2 scannés, zéro scatter search) → jumeau **construit** (subclass `Optimizer` pinnant le template Glover 1998 : combinaison convexe λ~U(0,1) par enfant, mate aléatoire sans soi, RefSet b1-qualité/b2-diversité max-min RMS vectorisée) ; 3 bras × 4 graines {0,1,7,42} × 3 répétitions, pop 50, 160 gén/epochs, budget mesuré 7 998-8 050 évals, sanity check coût IDENTIQUE (3 témoins LCG), contre-vérif croisée IDENTIQUE, déterminisme 12/12 ; verdict — **le jumeau mealpy gagne les deux mains** : qualité 51,5 [48-53] vs complet 54,0 [43-56] (étendue la plus resserrée de l'Epic) et vitesse 0,92× par éval (première défaite vitesse de MGS dans l'Epic, sur le bras qui porte le max-min non vectorisé — l'ablaté pur reste 4,7× moins cher) ; **axe diversité b2 signe-ambivalent par graine, défavorable en médiane** (ablaté 52,0 [45-56] vs complet 54,0, graine 42 inversée), fitness isolée C# 5,25× ; lecture : sans sa couche mémétique différée (Glover : improvement optional), le SS est le moteur le plus faible de l'Epic sur Sudoku-R1 et sa diversité de RefSet ne le sauve pas à ce budget | ~35 min | -| 31 | [MGS-31-Synthese-Croisee](MGS-31-Synthese-Croisee.ipynb) | **Synthèse croisée des 9 paires MGS vs mealpy** — le verdict final de l'Epic, récolté sans re-run | parsing C# des outputs committés des neuf paires (regex à groupes nommés sur lignes de banc et résumés médiane/min/max ; tolérances accents et virgule décimale française), intégrité **re-dérivée 9/9** (chaque valeur récoltée re-réconciliée avec les résumés imprimés des paires : zéro écart) ; tableau croisé qualité × coût + deux graphiques SVG (médianes par paire, ratios ms/éval en échelle log) ; verdict — **coût systématique** : mealpy plus cher par évaluation 8/9 (médiane 2,38x, jusqu'à 7,86x, inversion P1 documentée) = écart de runtime isolé par les tests fitness-seule (5,13x-5,33x) ; **qualité spécifique** : mealpy 6/9, MGS 3/9 (−6,5 à +17 conflits médians) ; bras de décomposition en preuve d'isolation (P7 jumeaux mealpy identiques à formules distinctes → noyau ; P9 ablation battant le complet → stratégie) ; limites disclosed : checkpoints 2/9, un seul paysage Sudoku 36 gènes, 4 graines, un seul budget | ~15 min | - -Les 8 figures MGS-7b (heatmaps de la projection N-D des paysages Sphere/Rastrigin/Schwefel) sont cataloguées dans [`assets/readme/MANIFEST.md`](assets/readme/MANIFEST.md) avec leurs **descriptions visuelles** verbatim (audit vision MiniMax M3 c.755, doctrine #5780) — voir notamment la note disclosed sur la convergence visuelle des heatmaps Rastrigin-d2/d10/d30 en projection MAX (moyennes RGB identiques à 2 décimales près). - -### Applications spécialisées - -Les notebooks d'application GA (détection de bords, optimisation de portefeuille — variants PyGAD Python et GeneticSharp C#) sont rassemblés dans la section [`Applications/Hybrid/`](../Applications/README.md) : **App-9 / App-9b** (EdgeDetection) et **App-10 / App-10b** (Portfolio). La série MGS numérotée (MGS-1 à MGS-19, MGS-21 à MGS-31, plus la trilogie de ponts MGS-7b/7c/7d de projection N-D ; MGS-20, langage de composition, est en préparation) constitue l'unique contenu propre à la Partie 4. - -La série suit un fil continu plutôt qu'un catalogue : on **reconstruit** les composés publiés depuis leurs primitives (MGS-5), on les **confronte** honnêtement (MGS-6, MGS-7), puis on apprend à *voir* le paysage (MGS-8, MGS-9), à *mesurer* ses biais (MGS-10 à MGS-14), à le *quantifier* (MGS-15), à *raisonner* sur le choix de l'algorithme (MGS-16), de ses paramètres (MGS-17), du protocole d'évaluation (MGS-18), la démontabilité d'un composé (MGS-19) — et enfin à *questionner la représentation elle-même* (MGS-21 : le croisement représentation × algorithme montre que le choix de l'espace peut dominer le choix du moteur). Le déroulé notebook par notebook figure dans le « Parcours détaillé » plus bas, et la Conclusion reprend les enseignements transversaux. Feuille de route du fork : [ROADMAP.md](https://github.com/jsboige/MetaGeneticSharp/blob/main/ROADMAP.md). - -L'arc se résume en onze vagues conceptuelles, chacune posant la brique que la suivante compose : - -```mermaid -flowchart LR - W1["Socle & composition
MGS-1 — Moteur autonome
MGS-2 — Grammaire fluente
(Match, Container, Scoped)"] - W2["Structuration de population
MGS-3 — Eukaryote
(sous-populations)
MGS-4 — Islands (migration)"] - W3["Composés publiés & confrontation
MGS-5 — Reconstruire WOA/EO/FBI
MGS-6 — Benchmarks
(No-Free-Lunch)
MGS-7 — TSP combinatoire"] - W4["Paysages de fitness
MGS-7b/7c/7d — Projection N-D
MGS-8 — Landscape Explorer
MGS-9 — Everest (relief réel)"] - W5["Biais & mesure falsifiable
MGS-10 — Biais central
(Kudela 2022)
MGS-11 — Synergie d'îles
(verdict négatif)"] - W6["Rotation & retour critique
MGS-12 — Alignement d'axes
MGS-13 — Paysages dé-biaisés
MGS-14 — Synergie conditionnelle"] - W7["Nombre & sélection (capstone)
MGS-15 — Métriques de paysage
(FDC, autocorrélation)
MGS-16 — Sélection d'algorithme
(Rice 1976, No-Free-Lunch)"] - W8["Contrôle du paramètre
MGS-17 — Parameter Control
(Eiben 1999)
tuning vs control
(déterministe / adaptatif / self-adaptatif)"] - W9["Banc CEC consolidé
MGS-18 — shift + rotate combinés
(protocole CEC)
biais composés
(sub- vs super-additif)"] - W10["Recuit démonté
MGS-19 — Metropolis isolé
du compound SA
opérateur fonctionnel
bénéfice = couplage"] - W11["Représentation vs algorithme
MGS-21 — plan croisé Sudoku
R1 continue+arrondi vs
R2 permutations
l'espace peut dominer le moteur"] - W1 --> W2 --> W3 --> W4 --> W5 --> W6 --> W7 --> W8 --> W9 --> W10 --> W11 -``` - -## Configuration requise - -Le kernel `dotnet-interactive` installé (**1.0.707101**, hôte .NET moderne) **charge nativement les assemblies `net9.0`** — vérifié par exécution : MGS-6 (qui référence `MetaGeneticSharp.Extensions` net9.0), MGS-18, MGS-19 et MGS-21 s'exécutent verts sur ce kernel. Les notebooks MGS se répartissent sur deux TFM : - -- **MGS-1 à MGS-5** (Introduction, Composition, Eukaryote, Islands, Compound) ne consomment que `MetaGeneticSharp.Domain` + `Infrastructure` + `GeneticSharp`. Ils référencent les **DLL `net8.0`**, chargées par rétro-compat sur le kernel actuel (qui supporte net8.0/net9.0/net10). -- **MGS-6 à MGS-9** (Benchmarks, TSP, Landscape, Everest) dépendent en plus de `MetaGeneticSharp.Extensions` (SkiaSharp / `System.Drawing.Common`). Ils référencent les DLL `net9.0` et **s'exécutent sur le kernel actuel** (MGS-6 vérifié vert). *Sur l'ancien kernel 1.0.552801 (hôte net8.0-only), ils restaient bloqués* (follow-up historique désormais non requis sur le kernel actuel). - -Règle : pas de contournement, installer l'environnement complet : - -```powershell -# 1. .NET SDK (9.0 requis pour le fork source ; 8.0/10.0 optionnels) -dotnet --version - -# 2. dotnet-interactive (kernel Jupyter pour C#, hôte .NET moderne >= 1.0.707101) -dotnet tool install --global Microsoft.dotnet-interactive -dotnet interactive jupyter install - -# 3. Sous-modules + build du fork (les notebooks chargent les DLL par #r absolu) -cd MyIA.AI.Notebooks/Search/MetaGeneticSharp -git submodule update --init --recursive -dotnet build # build net9.0 (fork source ; DLLs pour MGS-6..18) -``` - -> **Bins `net8.0` pour MGS-1..5.** Le fork est actuellement single-TFM `net9.0`, donc `-p:TargetFramework=net8.0` échoue (le `project.assets.json` restauré ne contient que la cible net9.0). Pour produire `Domain` + `Infrastructure` en `net8.0` (référencés par MGS-1..5, chargés par rétro-compat sur le kernel actuel), il faut soit retargeter temporairement le `.csproj` en `net8.0` puis `dotnet build`, soit — solution propre — multi-targeter le fork en `net8.0;net9.0` (follow-up sur le fork, `Extensions`/SkiaSharp restant net9.0-only). Les bins référencés par MGS-1..5 doivent exister sous `src/MetaGeneticSharp.Domain/bin/Debug/net8.0/`. - -Les notebooks chargent les DLL via `#r "c:/dev/MetaGeneticSharp/..."` (chemin du checkout de travail du fork). **MGS-1..5** pointent sur `src/MetaGeneticSharp.Domain/bin/Debug/net8.0/` (4 DLL : GeneticSharp.Domain, GeneticSharp.Infrastructure.Framework, MetaGeneticSharp.Domain, MetaGeneticSharp.Infrastructure) ; **MGS-6..14** pointent sur `src/MetaGeneticSharp.Extensions/bin/Debug/net9.0/` (Extensions + SkiaSharp + System.Drawing.Common) ; **MGS-21..28** pointent sur `src/MetaGeneticSharp.Domain/bin/Debug/net9.0/` (GeneticSharp.Infrastructure.Framework + MetaGeneticSharp.Infrastructure + MetaGeneticSharp.Domain, chemins relatifs `../MetaGeneticSharp/...`). - -**Reproductibilité.** Les résultats numériques de MGS-1 à MGS-9 sont **stochastiques** (le RNG du framework n'y est pas seedé) : les outputs committés sont une exécution valide, les valeurs varient d'une exécution à l'autre. À partir de MGS-10, les bancs sont seedés pour devenir **reproduisibles** : - -| Notebook | Strategy | Verdict | -|----------|----------|---------| -| **MGS-10** | `ResetSeed(masterSeed)` une fois avant la suite | reproduisible (biais central) | -| **MGS-11** | `ResetSeed(42)` avant chaque banc | reproductible (caveat : graine unique, pas multi-graines) | -| **MGS-12** | reseed avant chaque paire optimiseur | reproductible (caveat : dim 2, budget large → $\Delta \approx 0$ pour tous ; cf exercice 2) | -| **MGS-14** | multi-seed (5 graines) avant chaque archipel | reproduisible (synergie robuste sur Ackley, absente sur Rastrigin) | -| **MGS-17** | multi-seed (5 graines {7,42,99,123,777}) | reproduisible (`DynamicProbability` déterministe, pas de RNG interne) | -| **MGS-19** | multi-seed (3 graines {7,42,99}) avant chaque course | reproduisible (banc Metropolis-vs-Pairwise + limite frozen) | -| **MGS-21** | multi-seed (4 graines {0,1,7,42}) par cellule du plan croisé, `FastRandomRandomization.ResetSeed(seed)` avant création de population | reproduisible (croisement 2×2, 4/4 résolutions en R2/GA, déterminisme vérifié sur 3 exécutions) | - -Règle C.2 : les notebooks sont committés **avec leurs outputs** (exécution réelle, kernel .NET). - -## Parcours détaillé - -### 1 — Introduction - -Pourquoi un moteur autonome au-dessus de GeneticSharp ? Le notebook pose le contrat : un `MetaGeneticAlgorithm` qui pilote l'évolution sans dépendre de la classe `GeneticAlgorithm` amont, et un `IMetaHeuristic` qui intercepte chaque étape. On compare `DefaultMetaHeuristic` (reproduit le comportement GA classique) à `NoOp` (ne fait rien — l'observateur passif) sur un fitness quadratique simple. C'est le socle : tout le reste de la série compose au-dessus de ce moteur. - -### 2 — Composition - -Le cœur de la thèse « composants > métaphores ». On introduit `Match` (dispatch déclaratif sur le contexte d'évolution) et les primitives de contrôle-flux, puis on assemble une métaheuristique en quelques lignes lisibles. Ce notebook établit la grammaire fluente (`Match`, `Container`, `Scoped`) que WOA et EO réutiliseront plus tard comme briques plutôt que comme monolithes. - -### 3 — Eukaryote - -On cesse de traiter la population comme un sac homogène. Le modèle eucaryote partitionne la population en sous-populations spécialisées portées par des chromosomes composites — chaque compartiment peut avoir sa propre métaheuristique. C'est une configuration qu'aucune bibliothèque monolithique grand public n'offre directement, et qui devient naturelle une fois la composition maîtrisée. - -### 4 — Islands - -Le modèle insulaire structure la population en îles migratoires : chaque île évolue indépendamment, puis des individus migrent périodiquement. La primitive `IslandMetaHeuristic` assemble ce schéma à partir des mêmes briques que les notebooks précédents. La leçon : la diversité structurée (vs une population panmictique) change la dynamique de convergence. - -### 5 — Métaheuristiques composées - -D'où viennent les algorithmes « publiés » — Whale Optimization (WOA), Equilibrium Optimizer (EO), Forensic-Based Investigation (FBI) — et comment les utiliser sans retomber dans le piège de la boîte noire ? Ce notebook montre, pour chaque composé du catalogue, le même parcours en trois temps : **(1) la description** — la métaphore et la mécanique, dans l'esprit des fiches de `mealpy` ; **(2) la reconstruction depuis les primitives** — le corps réel de la méthode `BuildMainHeuristic()` qui assemble l'algorithme à partir de briques (`IfElse`, `Match`, `GenerationMetaHeuristic`, croisements géométriques), lu transparentement ; **(3) le raccourci factory** — le one-liner `MetaHeuristicsService.CreateMetaHeuristicByName("...")` qui produit *exactement* cette reconstruction, avec la preuve (le type racine renvoyé) que raccourci et reconstruction sont identiques. C'est l'argument « composants > métaphores » poussé jusqu'à la **preuve d'équivalence** : reconstruire un algorithme bio-inspiré *démontre* son mécanisme au lieu de le cacher derrière une métaphore animale (critique de Sørensen, 2015). Les benchmarks de MGS-6 mettent ensuite ces composés à l'épreuve. - -### 6 — Benchmarks - -La confrontation honnête. Dix fonctions standard (`KnownFunctions.cs` : Sphere, Rastrigin, Rosenbrock, Ackley, Griewank, Schwefel, Michalewicz, Zakharov, Booth, Dixon-Price) servent de paysages de test. On compare trois configurations — Uniform, WOA-reconstruit-depuis-les-primitives, Islands — et on rapporte les résultats sans trier les victoires : WOA gagne ou égalise sur 7/10, **diverge sur Schwefel** (le contrôle-flux géométrique sans clamp de bornes explose sur [-500, 500]). Cette divergence n'est pas un bug caché : l'inspectabilité du composé (on lit l'`IfElse` du bubble-net) en fait une démonstration de No-Free-Lunch, là où `mealpy` masquerait le mécanisme. - -### 7 — TSP combinatoire - -La grammaire de composition est-elle agnostique à la représentation ? MGS-1 à 6 opèrent sur des surfaces *continues* (gènes en `double`), mais les primitives structurantes (`Match`, `Container`, `Scoped`, `Islands`) vivent *sous* la couche géométrique. Ce notebook applique la **même** `IslandMetaHeuristic` à un problème de **permutation** — le Voyageur de Commerce sur 20 villes, gènes = index entiers — **sans aucune adaptation** : le modèle insulaire opère sur `IChromosome` et ne lit jamais `Gene.Value`. La comparaison reste honnête (G.9) : la baseline panmictique bat les Islands sur cette instance TSP-20, illustration de No-Free-Lunch — le point n'est pas la victoire mais le **transfert sans réécriture** de la grammaire d'une géométrie continue à un espace combinatoire. Setup : `TspFitness`, `OrderedCrossover` (OX1), `ReverseSequenceMutation`. Au-delà des îles, ce notebook éprouve aussi la **théorie des croisements géométriques de Moraglio** (2007) — un crossover est *géométrique* si sa progéniture reste sur le segment géodésique entre les parents, pour une métrique donnée. Or une permutation admet **plusieurs métriques naturelles**, et le fork en câble deux : la distance de **swap** (Cayley : combien de transpositions séparent deux ordres), réalisée par `OrderedEmbedding` (Config 3), et la distance d'**insertion** (Ulam : combien d'éléments déplacer en décalant les autres), réalisée par `InsertionEmbedding` (Config 4). La Config 4 démontre le point central du *deep learning géométrique* : depuis le parent `[0,1,2,3,4]` vers une même cible-permutation `[2,0,1,3,4]`, un pas de swap atteint `[2,1,0,3,4]` là où un pas d'insertion atteint `[2,0,1,3,4]` — deux **géodésiques distinctes**, donc deux descendants distincts atteignables en un seul croisement. **C'est l'embedding (le choix de la métrique) qui porte la géométrie, pas le moteur** (`GeometricCrossover`) ni l'opérateur (le centroïde) : changer uniquement d'embedding change le paysage exploré. Cadrage honnête (G.9) : ni swap ni insertion n'a de privilège géographique sur ce TSP (ce sont des distances sur les étiquettes d'indice, pas sur les coordonnées des villes) — les deux sont des baselines, et le centroïde naïf à deux parents borne symétriquement les deux métriques (limite déjà documentée en Config 3) ; un embedding appris équivariant par permutation ferait mieux que les deux. - -### 7b — Projection N-D des paysages - -MGS-6 a présenté les dix fonctions canoniques en 2-D. Mais une **vraie métaheuristique** optimise dans des dimensions bien supérieures (Rastrigin est intéressant à $n=30$, Schwefel a un optimum trompeur en $n \geq 10$). Ce notebook pont active la **surcharge N-D** de `KnownFunctionLandscape.RenderHeatmap` — la même rampe de couleurs, la même `SkiaLandscapeRenderer`, mais sur une dimension arbitraire : pour chaque pixel du canvas 2-D, `nbSamples` tirages uniformes des coordonnées cachées $x_2 \dots x_{N-1}$ et on garde le **MAX** (l'opérateur verbatim du contrôleur Gtk# original de jsboige). La projection rend lisibles des phénomènes invisibles en 2-D : la **Sphere** 5-D garde $(0,0)$ comme candidat d'optimum mais le MAX sur les coordonnées cachées fait émerger d'autres pixels ; **Rastrigin** en $n=2/5/10/30$ montre la densité de minima locaux croître avec la dimension (la heatmap rougit) ; **Schwefel** en $n=5/30$ fait émerger le *vrai* optimum global, loin du centre, dès qu'on autorise les coordonnées cachées à varier. C'est le pont entre la visualisation 2-D de MGS-6/MGS-8 et la réalité haute-dimension où vit l'optimisation — et le terrain où la projection N-D (capacité distinctive du renderer fork) est *nécessaire*, pas optionnelle. - -### 7c — Projection N-D : Rosenbrock (vallée banane) et Griewank (produit-cosinus) - -MGS-7b a projeté les quatre fonctions les plus classiques (Sphere, Rastrigin, Schwefel, Ackley). Ce second notebook pont poursuit l'exploration en haute dimension avec deux fonctions au comportement **structurellement différent** : **Rosenbrock** — la *vallée-courbe-étroite banane* — dont l'optimum serpente le long de la diagonale $x_i \approx 1$, et **Griewank**, dont le terme cosinus est un **produit** $\prod \cos(x_i/\sqrt{i})$ (et non une somme comme Ackley), générant en 2-D des bandes ondulantes perpendiculaires. La projection N-D $n=2/5/30$ révèle deux phénomènes que la 2-D masque : la vallée de Rosenbrock, **étroite** (largeur $\sim 10^{-2}$), devient quasi-invisible en 30-D (la probabilité qu'un tirage tombe *dans* la vallée est faible, la MAX-projection retient donc presque toujours une fitness hors vallée) ; Griewank, lui, voit son produit de 30 cosinus s'effondrer vers une surface lisse (le produit de nombreux termes $<1$ décroît vite). Deux leçons géométriques qui justifient la projection N-D : la dimension change la *visibilité* d'une structure fine, et produit vs somme ne se projettent pas pareil. - -### 7d — Projection N-D : Michalewicz (crêtes raides) et Dixon-Price (vallée non-scalable) - -Le troisième notebook pont referme la trilogie sur les deux dernières fonctions canoniques au comportement discriminant : **Michalewicz** — dont le paramètre $m=10$ dans $\sin^{2m}(\cdot)$ sature l'amplitude entre 0 et 1, créant des **crêtes quasi-binaires** alternant bandes sombres et claires (et dont l'optimum *dépend de la dimension* $n$, propriété rare) — et **Dixon-Price**, dont la vallée étroite est **parabolique-croisée** (le couplage $2(2x_2^2 - x_1)^2$ impose que $x_2$ suive $x_1$ selon une racine, pas selon $x_1^2$ comme Rosenbrock), donc **non-rectiligne** : étroite en haut, elle s'évase en bas. En projection N-D $n=2/5/30$, le paramètre $m=10$ rend chaque dimension presque discontinue (la MAX-projection retient les crêtes les plus marquées), et le couplage cross-dimension de Dixon-Price défait toute lecture coordonnée-par-coordonnée. La trilogie MGS-7b/7c/7d couvre ainsi les **huit fonctions canoniques** du banc en projection N-D — le terrain complet où la dimension révèle ce que la 2-D dissimule. - -### 8 — Fitness Landscape Explorer - -Tant que la surface de recherche est invisible, le choix d'une métaheuristique relève du doctrinal ; la visualiser le rend éclairé. Ce notebook consomme la bibliothèque `LandscapeRenderer` du fork — récupérée **byte-exact** depuis le *Landscape Explorer* original de jsboige (branche Metaheuristics @ `d05826fd`, PR giacomelli/GeneticSharp#87) — pour produire de **vraies heatmaps PNG graphiques** : `RenderHeatmap` peint chaque pixel selon la valeur de fitness (rampe rouge = haut / cyan = bas, minimum global Blanc, maximum global Noir) et `Plot` superpose les individus (BlueViolet) et le meilleur (Aqua). Trois modes de paysage sont couverts : **(1) fonction analytique** (les **vraies** `KnownFunctions`, p. ex. Sphere), **(2) carte d'altitude** — les **quatre cartes originales de jsboige** (Everest, Népal-Bhoutan, Plateau tibétain, Monde), récupérées byte-exact et embarquées comme ressources, lues comme champs de fitness via la verbatim `ImageHeightMapFunction` — et **(3) image custom** (un bitmap bimodal synthétique). La trajectoire de convergence du GA se superpose à la heatmap. Un wrapper `ShiftedFitness` translate l'optimum hors du centre pour rendre le **center-bias** visible : le GA converge sur l'optimum déplacé (≈ (2, 2)), preuve d'une recherche authentique. Les PNG sont encodés en base64 et affichés via `display(HTML(...))` — fiable sous papermill .NET (références DLL locales du fork, pas de `#r "nuget:"`). - -[![Convergence du GA sur Rastrigin multimodal (flipbook animé GIF89a, 7 frames × 400 ms ≈ 2.8 s) : le nuage de population BlueViolet se contracte génération après génération, depuis une large dispersion (frame 1, ~50 points répartis sur toute la grille) jusqu'à un cluster compact au voisinage du minimum global (frame 7, ~30 points regroupés au centre). Le paysage de fond (Rastrigin multimodal) reste visible sur toutes les frames.](assets/readme/mgs8-convergence.gif)](MGS-8-LandscapeExplorer.ipynb) - -### 9 — Trouver l'Everest : relief réel - -L'aboutissement : le paysage n'est plus synthétique mais un **relief terrestre réel**, et en **vraie résolution**. Les quatre cartes d'altitude sont les **assets verbatim de jsboige** (`KnownHeightMap.{World, TibetanPlateau, NepalBhoutan, EverestMount}`, PNG ~2560 px, acquis à l'origine depuis un service d'élévation WMS) — récupérés **byte-exact** sur le fork @ `d05826fd` et lus par la classe verbatim `ImageHeightMapFunction` (niveaux de gris = altitude, interpolation inverse-distance). Pas de grille `int[]` rééchantillonnée, pas de downsampling ETOPO1 : le PNG haute-définition **est** le champ de fitness. La classe pédagogique `DemGrid` n'est qu'une enveloppe *drop-in* sur `ImageHeightMapFunction` (elle expose `Interp`/`GlobalMax`/`ElevMin`/`ElevMax`) ; aucune logique d'optimisation n'y vit. On **maximise** le niveau de gris — le pixel le plus clair est le sommet — sur quatre cartes à zoom croissant (Monde → Plateau → Himalaya → Everest : le pic se resserre à mesure qu'on zoome). On lance le moteur MGS (GA / WOA / Equilibrium Optimizer) plus une baseline **PSO** externe à budget d'évaluations égal, et on mesure le **taux de réussite** de chaque méthode à localiser le sommet, relié au rapport taille-du-bassin / résolution. Un **flipbook de convergence** (même orchestration `GenerationRan` qu'en MGS-8) montre ensuite la population se contracter génération après génération vers le sommet sur la région Everest. Rendu en **heatmaps PNG graphiques** via le même `SkiaLandscapeRenderer` du fork que MGS-8 (cohérence intra-série, rendu SkiaSharp cross-platform), avec la **cible inversée** : MGS-8 *minimise* ses fonctions analytiques (l'optimum porte le marqueur Blanc) ; MGS-9 *maximise* l'altitude, donc c'est le **sommet** qui porte le **marqueur Noir** — la cible explicite de la recherche. - -[![Relief terrestre réel comme paysage de fitness : carte d'altitude de l'Everest, le sommet (pixel le plus clair) est la cible](assets/readme/mgs9-everest.png)](MGS-9-EverestRelief.ipynb) - -### 10 — Biais central - -MGS-6 montrait qu'aucune métaheuristique publiée ne bat la composition en performance brute ; MGS-10 ajoute une **seconde preuve**, plus profonde, en mesurant un défaut que la performance masque : le **biais central**. Le notebook câble le banc `CenterBiasBenchmark` du fork (protocole *centré-vs-déplacé* de Kudela, 2022) : chaque optimiseur est lancé sur une même fonction (Sphere, Rastrigin, Ackley ; dimension 5, NFE = 5000) en deux versions, l'optimum au **centre** puis **relocalisé** hors centre via `ShiftedFitness`. La signature $\Delta = f^\star_{\text{déplacé}} - f^\star_{\text{centré}}$ révèle si l'optimiseur résout la fonction *où que soit l'optimum* ($\Delta \approx 0$, non biaisé — la recherche aléatoire uniforme en est le contrôle canonique) ou s'il n'exploite que le placement central ($\Delta \gg 0$, biaisé vers le centre). Huit optimiseurs sont confrontés : **Random** (contrôle *seedé* `seed:7`, la référence non biaisée), **GA**, et les six composés géométriques **WOA, EO, FBI, Differential Evolution, Bare-Bones PSO, Recuit simulé** (Metropolis, 1953 ; Kirkpatrick, Gelatt & Vecchi, 1983). **Reproductibilité.** Le banc est **seedé** : `FastRandomRandomization.ResetSeed(masterSeed)` ancre le RNG global du framework une fois avant la suite, de sorte que les chiffres committés sont **reproduisibles** d'une exécution à l'autre — un étudiant qui ré-exécute le notebook retrouve exactement la table ci-dessous (le contrôle `Random` reste seedé séparément, `seed: 7`). - -Lecture honnête (G.9), fonction par fonction. **Sphere** (unimodale lisse) : tous les optimiseurs résolvent les deux cas (~0) → $\Delta \approx 0$ partout ; fonction trop facile pour révéler un biais. **Rastrigin** (fortement multimodale) : les $\Delta$ sont **bruités** — le contrôle Random lui-même y affiche le $\Delta$ le plus élevé (+7,9) ; à NFE = 5000 l'optimiseur tombe dans un optimum local différent selon le tirage, donc le $\Delta$ y mesure de la variance d'échantillonnage, pas un biais directionnel (la colonne *moyenne* qui agrège les trois fonctions est dominée par ce bruit et n'est pas un signal fiable). **Ackley** (puits central entouré de rides — la fonction *conçue* pour exposer le biais central) : **seul WOA** affiche $\Delta \gg 0$ (+4,36) — il résout Ackley centrée (~0) mais **rate** Ackley déplacée (4,36), signant un biais central net ; tous les autres (GA, EO, FBI, DE, BBPSO, Recuit simulé) résolvent les deux cas (~0) et sont **robustes** au déplacement. Leçon affûtée de « composants > métaphores » : ce n'est pas l'étiquette métaphorique (baleine, équilibre, criminalistique) qui prédit le biais — EO, FBI et BBPSO sont eux aussi « métaphoriques » mais robustes — c'est la **structure de l'opérateur**. L'encerclement de la meilleure position (le *bubble-net* de WOA) ancre la recherche sur le meilleur courant, qui sur une fonction à optimum central démarre près du centre → biais. Les opérateurs d'exploration arithmétique (**DE**, $v = r_1 + F \cdot (r_2 - r_3)$, même couche géométrique `GeometricCrossover`/`MatchMetaHeuristic` que WOA) et la perturbation gaussienne isotrope du **Recuit simulé** (critère de Metropolis) n'ancrent pas → robustesse. Ce n'est donc pas l'étiquette « métaphore » qui biaise vers le centre, mais l'ancrage de l'opérateur à un attracteur géométrique fixe. Leçon de lecture (honnêteté, G.9) : un $\Delta$ élevé n'est un *biais* que si l'optimiseur résolvait effectivement le cas centré ; sinon il signe juste de la faiblesse — d'où trois exercices (stabilité multi-graine de la signature, balayage de l'amplitude du déplacement, extension de la suite à Rosenbrock et Griewank). - -### 11 — Synergie d'îles complémentaires - -La composition est-elle **magique** ? Combiner un bon explorateur et un bon exploiteur dans un archipel hétérogène produit-il mécaniquement une synergie ? Ce notebook pose la question de façon **falsifiable** et y répond chiffres à l'appui. On assemble trois archipels de **même structure** (4 îles, migration `SmallMigrationRate`) via `IslandCompoundMetaheuristic` — (a) îles DE homogènes, (b) îles BBPSO homogènes, (c) 2 îles DE + 2 îles BBPSO hétérogène — et on les lance, à budget d'évaluations égal, sur Rastrigin et Ackley **dé-biaisées** en dimension 5 (optimum relocalisé hors centre via `ShiftedFitness` + `ShiftVectors.Seeded`). La dimension 5 (et non 2) est choisie pour que les opérateurs *différencient* : en dim 2, tous résolvent Rastrigin (objectif 0), rendant une synergie indiscernable. Un **GIF multicolore** (overlay `individualColors` + `EncodeAnimatedGif`) colore chaque individu par son île (DE en orange, BBPSO en vert) : la répartition exploration / exploitation devient visible génération après génération. **Verdict honnête (résultat négatif)** : sur les deux fonctions, l'archipel hétérogène est **battu** par le meilleur de ses constituants (0/2 synergie) — la migration entre opérateurs dissemblables peut *propager les solutions piégées* et produire un compromis *inférieur* au meilleur constituant. La synergie d'îles n'est pas automatique : elle se démontre, ne se décrète pas — la même leçon « composants > métaphores » (Sorensen 2015) poussée jusqu'à la *mesure* de la composition. Caveats : graine unique (pas un banc multi-graines ; banc rigoureux rote = #3963), GIF 2D illustratif alors que le banc est en dim 5. - -### 12 — Alignement d'axes - -MGS-10 instrumentait le biais **central** (un optimum à l'origine flatte les optimiseurs qui démarrent au centre) ; ce notebook instrumente le biais **complémentaire** des bancs CEC : l'**alignement d'axes**. On introduit le décorateur compositionnel `RotatedFitness` du fork — l'analogue de `ShiftedFitness` pour la rotation — qui évalue la fonction interne sur des coordonnées rotationnées $f_{\text{rot}}(x) = f(M x)$, où $M$ est une matrice orthogonale ($M M^\top = I$) fabriquée par le factory `RotationMatrices.Seeded(n, seed)` comme **produit de rotations de Givens** (orthogonale par construction, reproductible par $(n, \text{seed})$). Comme `ShiftedFitness`, c'est un décorateur fin : les mathématiques des fonctions canoniques sont réutilisées telles quelles (jamais réimplémentées), seules les coordonnées sont linéairement transformées. - -La **partie A** valide le décorateur contre la géométrie : sur Sphere (purement radiale, invariante par construction) la rotation est un no-op ; sur Rastrigin (terme $\sum \cos(2\pi x_i)$ séparable, un cosinus par axe) la rotation brise la séparabilité — la rotation *mesure* donc la séparabilité d'une fonction, c'est exactement pourquoi les suites CEC les rotationnent. La **partie B** montre la discrimination géométrique : sur Rosenbrock (asymétrique, vallée banane), la rotation conserve la *valeur* de l'optimum ($\approx 0$) mais en **déplace la position** — l'optimiseur aligné sur les axes ne peut plus descendre coordonnée par coordonnée. - -La **partie C** confronte les optimiseurs au banc : signature $\Delta = f^\star_{\text{roté}} - f^\star_{\text{non roté}}$ (le RNG est reseedé avant chaque paire pour isoler l'effet du paysage, pas du hasard). **Lecture honnête (G.9)** : en dimension 2 et à ce budget, $\Delta \approx 0$ pour **tous** — Rosenbrock 2D est assez facile pour que GA, WOA, DE, BBPSO la résolvent à zéro, rotationnée ou non ; il n'y a alors **pas de marge** pour qu'un alignement sur les axes pénalise. Un banc honnête ne « prouve » un biais opérateur que si le problème est assez dur pour que le biais ait de la place pour se manifester : ici le signal net est dans la **géométrie du paysage** (parties A/B), et complexifier le problème (dimension plus élevée, budget plus serré) pour révéler l'effet *opérateur* — un $\Delta$ qui sépare les déplacements composante par composant (crossover uniforme, WOA) des déplacements vectoriels (DE) — est précisément l'objet de l'exercice 2. On retrouve l'esprit de MGS-10 : on juge un optimiseur sur la **structure de ses opérateurs** (vectoriels vs composante par composant, centrés vs non), pas sur le nom de sa métaphore — et un banc honnête doit tester les **deux** biais CEC (`ShiftedFitness` + `RotatedFitness`, composables en la variante CEC complète `new RotatedFitness(new ShiftedFitness(inner, o), M)`). - -### 13 — Paysages dé-biaisés (visualisation) - -Là où MGS-12 *mesure* numériquement la signature d'alignement d'axes ($\Delta \approx +2847$ pour le GA sur Rastrigin rotatée contre $\approx +2$ pour le DE), ce notebook la **montre** géométriquement. On consomme le décorateur `RotatedFitness` ($f_{\text{rot}}(x)=f(M x)$, $M$ orthogonale) et l'on rend, en vraies heatmaps PNG via `SkiaLandscapeRenderer`, le paysage de fitness avant/après rotation. **Partie B — témoin de contrôle** : Sphere est invariante par rotation (une matrice orthogonale préserve la norme), les deux paysages sont donc identiques pixel pour pixel (écart numérique $\sim 10^{-15}$) — la validation que le décorateur est correct, toute différence observée plus loin provient bien de la géométrie. **Partie C** : la « vallée banane » de Rosenbrock pivote à 45°, l'optimum déménage de $(1,1)$ à $(\sqrt 2, 0)$, un terme croisé apparaît — la séparabilité est visiblement détruite. **Partie D** : les crêtes cosinus de Rastrigin basculent hors de la grille d'échantillonnage axe-par-axe — c'est le mécanisme géométrique exact derrière le $\Delta$ du GA mesuré en MGS-12. **Partie E** : la composition CEC `new RotatedFitness(new ShiftedFitness(inner, o), M)` combine déplacement et rotation ; l'optimum atterrit en $M^\top o$ et le paysage est doublement dé-biaisé. Les mathématiques canoniques ne sont jamais réimplémentées : seules les coordonnées sont transformées par les décorateurs compositionnels. Trois exercices prolongent (Ackley rotatée, recherche sur grille de l'optimum relocalisé, composition shift+rotate sur Schwefel). - -[![Rastrigin après rotation : les crêtes cosinus, alignées sur les axes à l'origine, basculent hors de la grille — la séparabilité est visiblement détruite](assets/readme/mgs13-rotation.png)](MGS-13-LandscapeDebias.ipynb) - -### 14 — Une synergie trouvée (et un cas négatif) - -MGS-11 avait **cherché** une synergie island-mix et l'avait honnêtement déclarée **absente** (0/2). Ce notebook revient sur ce verdict négatif avec une question de méthode : *était-ce l'absence de synergie, ou une migration mal calibrée qui diluait le meilleur îlot ?* Le modèle insulaire expose trois boutons (`GlobalMigrationRate`, `MigrationsGenerationPeriod`, ratio des îlots via les `shares`) ; MGS-11 les laissait par défaut (`SmallMigrationRate`, période 10) — un brassage qui noie le petit îlot exploitateur dans la population exploratrice avant qu'il n'ait fini de raffiner. Hypothèse : en réduisant le brassage (période 20) **et** en déséquilibrant le ratio (3 îlots DE explorateurs + 1 îlot BBPSO raffineur), l'îlot exploitateur survit assez pour exploiter ce que les explorateurs découvrent. - -Le banc est **multi-seed** (5 graines), à budget d'évaluations égal (1600 evals/archipel), sur Ackley et Rastrigin **dé-biaisées** en dimension 5, avec un **contrôle propre** : constituants (`DE-hom`, `BB-hom`) et combo candidate (`DE+BB-3:1`) partagent tous la même migration (`RandomRing`, taux 0.05, période 20) — seul le **ratio** varie, ce qui isole l'effet du ratio de l'effet de la migration. **Verdict mesuré** : sur Ackley, `DE+BB-3:1` bat **simultanément** ses deux constituants **5 graines sur 5** (fitness -0.309 vs DE-hom -2.302 et BB-hom -6.994) — la synergie est réelle et reproductible. Sur Rastrigin, `DE-hom` reste le meilleur et la même manipulation de ratio *dégrade* la fitness (-4.017 → -6.429) : **pas de synergie**. Leçon : la synergie island-mix existe mais est **conditionnelle** au paysage — Ackley (large cratère à puits profond) récompense l'exploration massive de DE *plus* le raffinement focalisé de BBPSO ; Rastrigin (forêt de minima réguliers) est mieux servi par l'exploration pure. Un **GIF multicolore** colore chaque individu par son îlot (DE orange, BBPSO vert) sur la convergence Ackley 2-D : on voit l'exploration orange se disperser puis converger, l'îlot vert raffiner sans être absorbé trop tôt. Un verdict négatif (MGS-11) n'est donc pas absolu — la bonne question n'est pas *« y a-t-il synergie ? »* mais *« à quelles conditions ? »*. Trois exercices prolongent (autre mode de migration, dimension 10, second cas de synergie sur Rosenbrock). - -### 15 — Le nombre derrière la heatmap : FDC globale + rugosité locale - -MGS-8 à MGS-13 nous ont donné l'**œil** : on *voit* la surface de fitness en couleur. Mais la visualisation est trompée par l'échelle, la rotation, le nombre de dimensions — deux paysages semblables peuvent être radicalement inégaux pour un algorithme. Ce notebook passe de l'**image au nombre** en introduisant la **Fitness Distance Correlation (FDC)** — Jones & Forrest (1995) — la métrique la plus utilisée pour prédire la difficulté d'un paysage. L'idée : un paysage est *facile* si la valeur de fitness est un bon indicateur de la distance au but ; tant que « mieux en fitness » rime avec « plus proche de l'optimum », un algorithme glouton ou génétique suit le gradient et converge. - -On calcule $\mathrm{FDC} = \rho(f(x), d(x, x^\star))$ (Pearson entre fitness brute et distance à l'optimum global) en **échantillonnant N points** uniformément dans la boîte de recherche, en **réutilisant la vraie infrastructure** de MGS-8 : le `DoubleArrayChromosome`, les bornes `KnownFunctionsBounds.For(...)`, et les **vraies** `IFitness.Evaluate` du fork (composition, jamais de réimplémentation — la fitness est celle du moteur, pas une recopie). Trois benchmarks contrastés où l'œil hésite : Sphere (unimodal), Rastrigin (multimodal), Ackley (structure fine). **Verdict FDC** : Sphere obtient FDC ≈ 0,976 (la fitness guide presque parfaitement, paysage facile), Rastrigin chute à 0,713 (les pièges locaux dispersent la relation fitness–distance), Ackley à 0,766 (intermédiaire). Le **nuage fitness–distance** rendu en SVG inline montre *pourquoi* : Sphere dessine un croissant propre (fitness ≈ distance²), Rastrigin disperse verticalement (à distance égale, plusieurs bassins). - -Mais la FDC ne mesure qu'une corrélation *globale* — elle ne dit rien de la **rugosité locale**. Le notebook introduit donc une **deuxième famille de métriques**, elle aussi réutilisant la vraie fitness du fork mais via une **marche aléatoire** (et non un tirage uniforme) : l'**autocorrélation de lag 1** $\rho_1$ (Weinberger 1990) et la **longueur de corrélation** $L = -1/\ln\rho_1$ — à quelle distance la fitness se décorréle-t-elle ? — ainsi que la **neutralité** (proportion de pas neutres, révélatrice des plateaux). **Verdict rugosité** : Sphere reste très lisse ($\rho_1 \approx 0{,}97$, $L \approx 30$ pas), Rastrigin s'effondre ($\rho_1 \approx 0{,}37$, $L \approx 1$ pas — le gradient local est du pur bruit, chaque pas décorréle), Ackley intermédiaire ($L \approx 10$). C'est l'explication **mécaniste** du verdict FDC : Rastrigin a une FDC basse non pas parce que sa fitness « ne guide pas » en moyenne, mais parce qu'à l'échelle locale elle **oscille** si vite qu'un glouton s'y empêtre. La **neutralité** rend un verdict honnête : quasi-nulle partout (~0–2 %) — ces benchmarks *continus* n'ont pas de plateaux, la métrique discrimine les paysages *discrets* (NK, SAT), pas ceux-ci. **Chaque métrique a son terrain** : les deux ensemble diagnostiquent ce que chacune, seule, masque — et justififie rétrospectivement pourquoi MGS-10 trouvait WOA biaisé sur Ackley (FDC intermédiaire *et* rugosité élevée : la fitness guide mal *et* oscille vite). Quatre exercices prolongent (FDC de Griewank, effet de la dimension, déception via Schwefel, rugosité de la vallée courbe de Rosenbrock). - -### 16 — Capstone : sélectionner le bon optimiseur (cadre de Rice, No-Free-Lunch) - -MGS-15 avait donné les **métriques** du paysage ; MGS-10 le **portfolio** mesuré de 8 optimiseurs. Ce notebook capstone referme la boucle : si aucun optimiseur ne gagne partout (théorème No-Free-Lunch, Wolpert & Macready 1997), alors le choix doit être *informé par le problème*. On applique le **cadre de sélection d'algorithme de Rice (1976)** — *features → algorithme du portfolio → performance* — en **réutilisant verbatim** l'infrastructure des deux notebooks précédents : le portfolio de 8 optimiseurs (Random, GA, WOA, EO, FBI, DE, BBPSO, SA via `MakeOptimizer` + `MetaHeuristicsService.CreateMetaHeuristicByName`) et les features de paysage (`Fdc`, `AutocorrLag1` via `RandomWalk`, `NeutralRatio`, `record LandscapeReport`). - -L'arc est celui d'une expérience complète : (1) **oracle** — le banc `CenterBiasBenchmark` (Kudela 2022) mesure le regret $\Delta$ des 8 optimiseurs sur Sphere/Rastrigin/Ackley (vérité terrain) ; on agrège en **pire-cas** (et non moyenne, bruitée par Rastrigin) : DE, BBPSO, EO sont robustes (aucune fonction où ils s'effondrent), WOA s'effondre sur Ackley ($\Delta = +4{,}19$ — exactement le biais central de MGS-10). (2) **Features** — on décrit les trois paysages *sans les optimiser* (FDC Sphere 0,99 / Rastrigin 0,74 ; $\rho_1$ Sphere 0,98 / Rastrigin 0,62). (3) **Sélecteur heuristique** — une règle lisible (Rice) qui, des features, recommande l'optimiseur adapté et signale ceux à éviter ; recoupée contre l'oracle, elle est **ALIGNÉE** sur les trois paysages et évite correctement WOA sur Ackley. (4) **Généralisation** — un quatrième paysage jamais vu, Rosenbrock (vallée banane) : le sélecteur recommande DE/BBPSO qui atterrissent dans le top-3 réel — mais la feature FDC s'y révèle **trompeuse** (Rosenbrock est unimodale et lisse, pourtant FDC ≈ 0,71 : la métrique radiale ne capte pas la *vallée courbe*). **Leçon honnête** : les features de paysage orientent vers les bons optimiseurs et écartent les catastrophes évidentes, mais elles manquent la géométrie directionnelle — un FDC bas signifie tantôt « multimodal » (Rastrigin) tantôt « courbé » (Rosenbrock), et la feature seule ne distingue pas les deux. C'est le **capstone** de la Partie 4 : on est parti de métaheuristiques isolées, on les a mesurées (portfolio), on a appris à décrire les problèmes (paysage), et l'on sait désormais faire correspondre les deux — le No-Free-Lunch n'est pas une condamnation mais l'invitation à *raisonner sur le problème avant de lancer l'algorithme*. Quatre exercices prolongent (paysage neutre quantifié, sélecteur fondé sur le coût d'évaluation, limite du FDC sur Schwefel, vers un sélecteur appris par k-NN). - -### 17 — Deuxième réponse au No-Free-Lunch : contrôler les paramètres pendant la course (Eiben 1999) - -MGS-16 répondait au No-Free-Lunch en **sélectionnant** le bon algorithme pour le paysage. MGS-17 donne la **seconde réponse classique** : un *même* algorithme, mais dont on **adapte les paramètres pendant la course**. C'est la distinction de Karafotias et al. (2015) — reprise d'Eiben et al. (1999) — entre le **tuning** (réglage *offline*, fixe, le pari « un taux pour toute la course ») et le **control** (adaptation *online*, dynamique). Trois types de control sont distingués par la taxonomie d'Eiben : **déterministe** (un schedule $p(g)$ fonction de la génération), **adaptatif** (un feedback de l'état de la population), **self-adaptatif** (le taux encodé *par individu*). - -Le notebook exploite le **vrai moteur du fork** — pas une réimplémentation. Le hook est `ProbabilityConfig.DynamicProbability : Func` combiné à `ProbabilityStrategy.OverwriteProbability` : à chaque évaluation, le solveur appelle `DynamicProbability(ctx, initial)` et **écrase** la probabilité de mutation du GA. Le `ctx` expose `Population.GenerationsNumber` (déterministe), les statistiques de population (adaptatif) et l'`OriginalIndex` de l'individu (self-adaptatif). C'est exactement la granularité que la taxonomie d'Eiben décrit — et le fork la fournit nativement. L'infrastructure est réutilisée verbatim depuis MGS-10/15/16 (`DoubleArrayChromosome`, `MakeOptimizer`, `RunAvg` sur 5 graines, `KnownFunctionsBounds`, `RastriginFitness`/`SphereFitness`). - -L'arc est une démonstration à quatre bras, **budgétée à parts égales** (mêmes NFE = 5000, mêmes 5 graines {7,42,99,123,777}, pour ne pas tricher par le budget) : (1) **tuning fixe** — un sweep $p \in \{0{,}01, 0{,}05, 0{,}20, 0{,}50\}$ sur Rastrigin, le meilleur est $p=0{,}05$ (objectif 11,885) ; leçon : aucun taux fixe n'est robuste. (2) **control déterministe** — un schedule de décroissance exponentielle $p(g) = 0{,}5 \cdot e^{-3g/G}$ (explore tôt, exploite tard), dont la trace imprimée montre la probabilité chuter de 0,500 à 0,025. (3) **control adaptatif** — la probabilité suit un signal de diversité (écart-type du 1er gène de la génération courante). (4) **control self-adaptatif** — chaque individu porte son propre taux (grille par index), la population est **hétérogène**. **La leçon centrale (No-Free-Lunch du paramètre)** : sur Rastrigin, le self-adaptatif gagne nettement (9,944 — il *hedging* : à chaque instant, une sous-population a le bon taux pour la phase courante, l'`EliteSelection` préserve le meilleur des deux mondes) ; mais sur Sphere, **l'ordre s'inverse** — le réglage fixe timide ($p=0{,}05$) et le decay mènent (0,750 / 0,711), le self-adaptatif est dernier (1,066) : la mutation qui aidait à *échapper* aux minima locaux de Rastrigin ne fait que *bruiter* la convergence facile de Sphere. Aucune stratégie ne domine sur les deux paysages. C'est le miroir exact de MGS-16 : là où l'algorithme était paysage-dépendant, ici c'est le **paramètre** — et l'honnêteté du banc (succès Rastrigin **et** échec Sphere) évite de réciter « le contrôle c'est toujours mieux » que les données démentent. Quatre exercices prolongent (schedule linéaire, règle 1/5 de Rechenberg par taux de succès, vrai chromosome self-adaptatif d'Évolution Strategies, contrôle du crossover). - -### 18 — Banc CEC consolidé : shift+rotate combinés, le protocole standard de dé-biais - -MGS-10 isolait le **décalage** de l'optimum, MGS-12 la **rotation** des axes. Les benchmarks *réels* du Congress on Evolutionary Computation (CEC) font les deux à la fois : une fonction est *à la fois* translatée et rotatée, et c'est cette composition qui définit le standard de test des métaheuristiques depuis CEC 2005/2017. MGS-18 **consolide** ce protocole : il confronte les 8 optimiseurs du portfolio (verbatim MGS-16) à **quatre variantes** — plain, shifted, rotated, **combined** — en étendant `CenterBiasBenchmark` (qui n'en proposait que deux). - -L'infrastructure est réutilisée verbatim : les décorateurs composes du fork `ShiftedFitness(inner, offset)` et `RotatedFitness(inner, M)` sont **composables** par construction — `RotatedFitness(ShiftedFitness(inner, Off), M)` applique la translation *puis* la rotation. `ShiftVectors.Seeded(n, magnitude, seed)` et `RotationMatrices.Seeded(n, seed)` (orthogonale via produit de rotations de Givens) garantissent la reproductibilité. La sanity check est **non dégénérée** (point test $x=(1,2,3,4,5)$ : les 4 variantes donnent 4 valeurs distinctes 9,70 / 12,20 / 10,72 / 13,05 — les décorateurs transforment bien la fonction). - -La thèse est **structurelle** : les biais isolés de MGS-10 et MGS-12 **se composent** sous shift+rotate combiné. Mais l'effet du combined est **paysage-dépendant**, pas universellement pire. Sur **Ackley** : EO, FBI et DE résolvent les 4 variantes (~0) ; WOA s'effondre sur le cas *shifted* seul (2,97 — son biais central MGS-10) et GA sur le *rotated* seul (3,24 — son biais d'axe MGS-12) ; le combined de WOA est **sub-additif** (2,73 < shifted 2,97 — la rotation masque le décalage). Sur **Rosenbrock**, l'histoire s'inverse : le combined de WOA (6,91) **dépasse** à la fois le shifted (5,19) et le rotated (3,13) — **super-additif** (+1,41 : les deux biais se renforcent). Aucun optimiseur ne domine les 4 variantes sur les 2 paysages : DE est le plus robuste (pire-cas 1,71), WOA et Random « à éviter ». L'honnêteté du banc (sub-additif sur Ackley **et** super-additif sur Rosenbrock) évite le faux cadrage « le combined aggrave toujours » — un récit plus riche, fidèle aux données. Quatre exercices prolongent (nouvelle rotation seedée, rotation non-orthogonale, grand-angle, banc CEC complet 10 fonctions). - -### 19 — Recuit simulé décomposé : l'opérateur de Metropolis isolé - -MGS-10 confrontait le **recuit simulé** comme une boîte noire. Mais dans le fork, `SimulatedAnnealing` n'est pas un monolithe : c'est un **composé** assemblant une **perturbation gaussienne** (le croisement qui produit un voisin de l'individu courant) et une **réinsertion de Metropolis** (`MetropolisReinsertion`) qui accepte ou rejette ce voisin selon le critère $P = \exp(\Delta / T_k)$. MGS-19 **débranche** ce deuxième ingrédient et le rebranche **seul** sur un GA standard (croisement de recombinaison `UniformCrossover`, pas perturbation), via l'injection `ga.Reinsertion = reins`. C'est la thèse « composants > métaphores » poussée jusqu'au **démontage du recuit lui-même** : la métaphore thermodynamique est-elle indivisible, ou l'opérateur de survie est-il réutilisable ailleurs ? - -Le banc isole l'effet de la **règle d'acceptation** à appariement constant : cinq configurations (`FitnessBasedPairwiseReinsertion` contrôle greedy, trois `MetropolisReinsertion` à températures froide/moyenne/chaude, `FitnessBasedElitistReinsertion` référence μ+λ) partagent le même croisement, la même mutation, la même sélection — seul le critère de survie varie. Budget commun (NFE = 5000, dim 5, 3 graines seedées → chiffres reproduisibles) sur Sphere (témoin neutre unimodal), Rastrigin et Ackley (multimodales). **Verdict honnête (résultat négatif, G.9)** : sur Sphere, l'annealing ne sert à rien (témoin neutre attendu) et le réglage chaud dégrade (≈ 0,10 contre ≈ 0,01) ; sur Rastrigin et Ackley, **aucun** réglage Metropolis n'améliore le contrôle greedy pairwise — le plus chaud est le **pire**. L'hypothèse naturelle (accepter des enfants moins bons aide à franchir les cols) est **réfutée**. L'explication la plus plausible est sémantique : dans SA l'enfant est un **voisin** du parent, donc accepter un moins bon voisin = explorer le voisinage ; ici l'enfant est un **recombinant** de deux parents (mosaïque par gène), donc accepter un recombinant moins bon n'est pas une exploration — c'est du bruit. **Le bénéfice du recuit réside dans le couplage** perturbation+acceptation, pas dans l'acceptation seule. C'est la leçon « composants > métaphores » dans sa forme la plus exigeante : on PEUT démonter SA, l'opérateur isolé FONCTIONNE sur le vrai moteur — mais il ne porte pas, à lui seul, le bénéfice du tout (écho de la synergie conditionnelle de MGS-11/14 : la composition n'est magique ni assemblée ni désassemblée). Une **limite frozen** (T→0 ⇒ règle greedy), vérifiée sur le témoin lisse Sphere (résidu = divergence de trajectoire RNG, non un effet d'acceptation), referme la cohérence. Trois exercices prolongent (schedule lent vs rapide, recombiner la perturbation pour restaurer le couplage, composition insulaire de l'opérateur). - -### 21 — Représentation vs algorithme : le plan croisé Sudoku - -MGS-16/17 répondaient au No-Free-Lunch en changeant *d'algorithme* ou *de paramètres*. Ce notebook pose la question en amont d'eux : **et si le facteur dominant n'était ni l'algorithme ni ses paramètres, mais la représentation ?** Sudoku-05 (Tranches 3 et 4) avait comparé des moteurs sur des représentations différentes *par morceaux*, sans pouvoir attribuer l'effet à l'un ou l'autre facteur ; MGS-21 mène l'expérience **croisée** propre : deux représentations — **R1**, le vecteur continu $[1,10)^{36}$ décodé par arrondi+clamp (chromosome `double` sur le vrai moteur MGS), **R2**, la grille où chaque ligne est une permutation des chiffres manquants (algèbre de swaps Move/Minus/Times de Hernandez & Gonzalez, *Metaheuristics in C#*, MIT 2012 — la vitesse est une liste de swaps sur cellules vides, chaque ligne reste une permutation par construction) — croisées avec deux moteurs, le **PSO** composé (`MetaHeuristicsService.CreateMetaHeuristicByName("ParticleSwarmOptimization")`) et un **GA** à permutations (croisement par lignes, mutation swap). Même grille (Easy[0] de Sudoku_Easy51, 36 vides), même fonction de coût (conflits lignes+colonnes+blocs), même budget (~8 000 évaluations), 4 graines {0,1,7,42} par cellule — et un **critère de verdict pré-enregistré** : « la représentation domine » exige que l'écart R1→R2 dépasse, dans chaque colonne, les écarts entre algorithmes. - -**Verdict honnête en deux temps (G.9)** : sur la colonne PSO, la représentation domine — la médiane passe de 45,0 à 6,0 conflits (−39), davantage que le meilleur effet algorithme ne le rapproche (−34,5) ; sur la colonne GA, les deux facteurs pèsent du même ordre (10,5 → 0,0 côté représentation, ×4,3 côté algorithme) — et seule leur **combinaison** R2×GA résout : **4/4 graines à 0 conflit**, aucune cellule R1 ne s'approchant de la solution (minimum 4). La cellule de **cause** explique pourquoi l'écart est structurel et non dynamique : 200 candidats R1 sur 200 (100 %) tombent hors de l'espace admissible après décodage (l'arrondi est une projection discontinue qui détruit l'information de proximité), contre 0/200 pour R2 par construction ; un candidat R1 aléatoire part à 67,9 conflits en moyenne contre 37,4 en R2 — les conflits de lignes que R2 rend *impossibles*, R1 les porte presque tous dès le tirage. C'est la version mesurée du geste « changer de représentation plutôt qu'insister » : avant de régler `w`, `c1` ou `c2`, demander ce que le décodage détruit. Trois exercices prolongent (rejouer le croisement sur une seconde grille, recuit simulé sur les deux représentations, diversité effective par grille décodée distincte). - -> Numérotation : MGS-20 (langage de composition, [#12224](https://github.com/jsboige/CoursIA/issues/12224)) est en préparation — MGS-21 a été livré indépendamment car le plan croisé ne dépend pas du langage de composition. - -## Conventions - -- **Représentation agnostique.** Les composés géométriques (WOA, EO) requièrent un chromosome qui stocke les gènes en `double` de façon transparente. Les notebooks définissent un `DoubleArrayChromosome` (assistant de test, non livré dans la lib) avec `CreateNew()` randomisant dans les bornes — indispensable pour la diversité initiale d'un benchmark. -- **Fitness = négation.** GeneticSharp *maximise* le fitness ; chaque `Evaluate()` des fonctions benchmark renvoie donc l'objectif nié. La lib pinne cette convention par [tests unitaires](https://github.com/jsboige/MetaGeneticSharp/blob/main/tests/MetaGeneticSharp.Extensions.Tests/KnownFunctionsTests.cs) (optimum à x* + négation). - -## Boucle CoursIA ↔ fork - -Le code de la bibliothèque vit dans le **fork** [jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp), monté ici comme sous-module (`MyIA.AI.Notebooks/Search/MetaGeneticSharp/`). Les notebooks pédagogiques (ce répertoire) sont propriété du dépôt CoursIA et consomment la bibliothèque via ses DLLs buildées. Ce point d'entrée ferme la boucle : depuis la série Search Python (Parties 1-2), on bascule vers le side track C#, qui redirige à son tour vers le fork pour le code source complet, les tests et la feuille de route. - -## Références - -Les métaheuristiques reconstruites dans cette partie suivent les articles fondateurs. Les liens bibliothèque (GeneticSharp, fork MGS) sont regroupés dans la section « Liens » ci-dessous. - -| Notebook(s) | Métaheuristique | Référence | -|-------------|-----------------|-----------| -| MGS-1 (Introduction) | Algorithme génétique | Holland, J. H. (1975) — *Adaptation in Natural and Artificial Systems*. University of Michigan Press. | -| MGS-5 (Compound), MGS-6 (Benchmarks) | Whale Optimization Algorithm | Mirjalili, S., & Lewis, A. (2016) — « The Whale Optimization Algorithm », *Advances in Engineering Software* 95. | -| MGS-5 (Compound), MGS-9 (EverestRelief) | Equilibrium Optimizer | Faramarzi, A., Heidarinejad, M., Stephens, B., & Mirjalili, S. (2020) — « Equilibrium optimizer: A novel optimization algorithm », *Knowledge-Based Systems* 197. | -| MGS-10 (CenterBias) | Differential Evolution | Storn, R., & Price, K. (1997) — « Differential Evolution – A Simple and Efficient Heuristic for Global Optimization over Continuous Spaces », *Journal of Global Optimization* 11. | -| MGS-10 (CenterBias), MGS-28 (BareBonesPSO-vs-Mealpy) | Bare-Bones Particle Swarm | Kennedy, J. (2003) — « Bare Bones Particle Swarms », *Proc. IEEE Swarm Intelligence Symposium*. | -| MGS-10 (CenterBias), MGS-19 (MetropolisReinsertion) | Recuit simulé (Simulated Annealing) | Metropolis, N., Rosenbluth, A. W., Rosenbluth, M. N., Teller, A. H., & Teller, E. (1953) — « Equation of State Calculations by Fast Computing Machines », *Journal of Chemical Physics* 21(6) ; Kirkpatrick, S., Gelatt, C. D., & Vecchi, M. P. (1983) — « Optimization by Simulated Annealing », *Science* 220(4598). | -| MGS-10 (CenterBias) | Test du biais central (centré-vs-déplacé) | Kudela, H. (2022) — protocole centré-vs-déplacé (centered-vs-shifted). | -| MGS-11 (IslandSynergy), MGS-19 (MetropolisReinsertion) | Modèle insulaire, synergie d'îles hétérogènes ; démontage d'un composé (composants > métaphores) | Sørensen, K. (2015) — « Metaheuristics—the metaphor exposed », *Intl. Trans. in Operational Research* 22(1). doi:10.1111/itor.12001 | -| MGS-9 (EverestRelief) | Particle Swarm Optimization (baseline) | Kennedy, J., & Eberhart, R. (1995) — « Particle Swarm Optimization », *Proc. IEEE Int. Conf. on Neural Networks*. | -| MGS-6, MGS-7, MGS-16 | No-Free-Lunch | Wolpert, D. H., & Macready, W. G. (1997) — « No free lunch theorems for optimization », *IEEE Trans. on Evolutionary Computation* 1(1). | -| MGS-16 (AlgorithmSelection) | Cadre de sélection d'algorithme | Rice, J. R. (1976) — « The Algorithm Selection Problem », *Advances in Computers* 15. doi:10.1016/S0065-2458(08)60520-3 | -| MGS-17 (ParameterControl) | Taxonomie tuning vs parameter control | Eiben, A. E., Hinterding, R., & Michalewicz, Z. (1999) — « Parameter Control in Evolutionary Algorithms », *IEEE Trans. on Evolutionary Computation* 3(2). doi:10.1109/4235.771166 | -| MGS-17 (ParameterControl) | État de l'art du parameter control | Karafotias, G., Hoogendoorn, M., & Eiben, A. E. (2015) — « Parameter Control in Evolutionary Algorithms: A Tutorial », *Evolutionary Computation* 23(2). doi:10.1162/EVCO_r_00136 | -| MGS-17 (Exercice 2) | Règle 1/5 (control adaptatif par succès) | Rechenberg, I. (1973) — *Evolutionsstrategie: Optimierung technischer Systeme nach Prinzipien der biologischen Evolution*. Frommann-Holzboog. (cf. Schwefel, H.-P. (1995), *Evolution and Optimum Seeking*, Wiley.) | -| MGS-18 (CecBanc) | Protocole CEC (shift+rotate composés) | Awad, N. H., Ali, M. Z., Suganthan, P. N., & Reynolds, R. G. (2016) — « Problem Definitions and Evaluation Criteria for the CEC2017 Special Session and Competition on Single Objective Real-Parameter Optimization », *Technical Report*, Royal Melbourne Institute of Technology. (suite de CEC2005 : Suganthan, P. N. et al. (2005).) | -| MGS-7 (Configs 3-4) | Croisement géométrique (Moraglio) | Moraglio, A. (2007) — *Towards a Geometric Unification of Evolutionary Algorithms*, PhD thesis, University of Essex. | -| MGS-21 (Representation) | Algèbre de swaps pour PSO discret (vitesse = liste de swaps) | Hernandez, A., & Gonzalez, Y. (2012) — *Metaheuristics in C#*. MIT, Universidad de La Habana (Common/DiscretePSO.cs). | - ---- - -## Conclusion / Prochaines étapes - -### Ce que vous avez appris - -Cette quatrième partie a changé la question : non plus *« quelle métaheuristique choisir »* (Parties 1-2), mais *« comment construire et combiner des métaheuristiques à partir de primitives »*. L'arc pédagogique, porté par trente-cinq notebooks C# .NET 9 au-dessus de [MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp), démontre la thèse **composants > métaphores** : - -- **Le moteur autonome** (MGS-1, MGS-2) — un `MetaGeneticAlgorithm` qui pilote l'évolution sans dépendre de la classe `GeneticAlgorithm` amont, et la grammaire fluente (`Match`, `Container`, `Scoped`) qui permet d'assembler une métaheuristique en quelques lignes déclaratives lisibles. C'est le socle : tout le reste compose au-dessus. -- **La structuration de population** (MGS-3, MGS-4) — le modèle eucaryote (sous-populations spécialisées portées par des chromosomes composites) et le modèle insulaire (îles migratoires) : deux configurations qu'aucune bibliothèque monolithique grand public n'offre directement, et qui deviennent naturelles une fois la composition maîtrisée. -- **La reconstruction des composés publiés** (MGS-5) — WOA, EO, FBI : pour chaque algorithme du catalogue, le parcours en trois temps (description → reconstruction depuis les primitives `BuildMainHeuristic()` → raccourci factory prouvant l'équivalence). C'est l'argument poussé jusqu'à la **preuve** : reconstruire un algorithme bio-inspiré *démontre* son mécanisme au lieu de le cacher derrière une métaphore animale (critique de Sørensen, 2015). -- **La confrontation honnête** (MGS-6) — dix fonctions benchmark standard, comparaison Uniform / WOA / Islands sans trier les victoires : WOA gagne ou égalise sur 7/10 mais **diverge sur Schwefel**, démonstration de No-Free-Lunch là où `mealpy` masquerait le mécanisme. -- **L'agnosticisme à la représentation** (MGS-7) — la même `IslandMetaHeuristic` appliquée à un TSP-20 (permutation) sans aucune adaptation : la grammaire vit *sous* la couche géométrique et ne lit jamais `Gene.Value`. Le transfert continu → combinatoire sans réécriture. Le notebook pousse plus loin la **théorie géométrique de Moraglio** (Configs 3 et 4) : deux métriques de permutation distinctes (swap/Cayley via `OrderedEmbedding`, insertion/Ulam via `InsertionEmbedding`) définissent deux segments géodésiques distincts entre les mêmes parents — preuve que **c'est l'embedding (le choix de la métrique) qui porte la géométrie, pas le moteur** : c'est le point du *deep learning géométrique* appliqué aux opérateurs génétiques. -- **La visualisation des paysages** (MGS-8, MGS-9) — de vraies heatmaps PNG (fonction analytique, carte d'altitude, relief terrestre réel Everest) qui rendent le choix d'une métaheuristique *éclairé* plutôt que *doctrinal*, et un flipbook de convergence montrant la population se contracter vers le sommet. -- **La caractérisation du biais central** (MGS-10) — le protocole centré-vs-déplacé (Kudela 2022) confronte huit optimiseurs (Random, GA, WOA, EO, FBI, DE, BBPSO, Recuit simulé) sur un banc **seedé** (chiffres reproduisibles). Lecture fonction par fonction : sur Sphere (trop facile) et Rastrigin (trop bruitée à NFE = 5000) le signal n'est pas fiable, mais sur **Ackley** — la fonction conçue pour exposer le biais — **seul WOA** présente un biais central ($\Delta = +4,36$ : il résout le cas centré mais rate le cas déplacé) ; les sept autres, y compris les composés « métaphoriques » EO, FBI, BBPSO, sont **robustes**. Leçon affûtée de « composants > métaphores » : ce n'est pas l'étiquette métaphorique qui prédit le biais — EO, FBI, BBPSO sont eux aussi métaphoriques mais robustes — c'est la **structure de l'opérateur** : l'encerclement de la meilleure position (WOA) ancre vers le centre, là où l'arithmétique libre (DE, Recuit simulé) ou le pool d'équilibre (EO) n'y ancrent pas. Une **seconde preuve**, plus fine, au-delà de la performance brute (MGS-6). -- **La mesure d'une synergie** (MGS-11) — la composition est-elle magique ? Un archipel hétérogène (îles DE exploratrices + îles BBPSO exploitantes) est confronté, à budget égal sur fonctions dé-biaisées en dim 5, à ses constituants homogènes. Verdict **négatif** (0/2 synergie) : la migration entre opérateurs dissemblables peut *propager les solutions piégées* et produire un compromis *inférieur* au meilleur constituant. La synergie d'îles n'est pas automatique — elle se **démontre**, ne se décrète pas : « composants > métaphores » poussée jusqu'à la *mesure falsifiable* de la composition. -- **La synergie retrouvée, et conditionnelle** (MGS-14) — retour critique sur le verdict négatif de MGS-11. En calibrant la migration (période 20 au lieu de 10) **et** le ratio exploration/exploitation (3 îlots DE + 1 îlot BBPSO), la combo `DE+BB-3:1` bat **simultanément** ses deux constituants sur Ackley, **5 graines sur 5** (contrôle propre : constituants et combo partagent la même migration, seul le ratio varie). Mais la même manipulation de ratio *dégrade* la fitness sur Rastrigin — la synergie est **conditionnelle** au paysage. Leçon de méthode : un verdict négatif n'est pas absolu, la bonne question est *« à quelles conditions ? »*, et un banc honnête rapporte succès (Ackley) **et** échec (Rastrigin). -- **Le capstone : sélectionner plutôt qu'invoquer** (MGS-16) — le No-Free-Lunch (Wolpert & Macready 1997) dit qu'aucun optimiseur ne domine ; le **cadre de Rice (1976)** (*features → portfolio → performance*) répond pragmatiquement. Le notebook **réunit les deux fils** — le portfolio de 8 optimiseurs (MGS-10) et les features de paysage (MGS-15) — et construit un sélecteur heuristique qui, des seules features mesurées, oriente vers les optimiseurs robustes (DE/BBPSO/EO) et **évite les catastrophes** (WOA sur Ackley, $\\Delta=+4{,}19$) sans avoir à tout exécuter. Validé sur les trois paysages connus, il est **éprouvé sur un quatrième jamais vu** (Rosenbrock) où la recommandation atterrit dans le top-3 réel — mais où le FDC se révèle trompeur (la vallée courbe n'est pas captée par la métrique radiale). C'est la fermeture de l'arc : décrire le problème (paysage) pour **faire correspondre** l'algorithme (portfolio), transformer le No-Free-Lunch d'une condamnation en méthode. -- **La deuxième réponse au No-Free-Lunch : contrôler le paramètre** (MGS-17) — là où MGS-16 changeait *d'algorithme* selon le paysage, MGS-17 garde le *même* algorithme et adapte ses **paramètres pendant la course** (taxonomie d'Eiben 1999 : tuning *fixe* vs control *déterministe* / *adaptatif* / *self-adaptatif*). Le notebook se branche sur le vrai moteur du fork — `ProbabilityConfig.DynamicProbability`, qui écrase la probabilité de mutation à chaque évaluation — et montre les trois types de control en acte : un schedule de décroissance, un feedback de diversité, des taux *par individu* (self-adaptatif hétérogène). La leçon est honnête : le contrôle **n'est pas universellement meilleur** — sur Rastrigin le self-adaptatif gagne nettement (il *hedging*, une sous-population a toujours le bon taux), mais sur Sphere **l'ordre s'inverse** (la mutation qui échappe aux minima de Rastrigin ne fait que bruiter la convergence facile de Sphere). **No-Free-Lunch au niveau du paramètre**, miroir exact de celui de l'algorithme (MGS-16) : les deux réponses classiques, ici réunies, disent la même chose — aucune stratégie n'est universelle, seul le *raisonnement sur le problème* (quel paysage ? quelle phase de course ?) l'est. -- **La consolidation du banc CEC : shift+rotate combinés** (MGS-18) — les benchmarks *réels* du Congress on Evolutionary Computation translatent **et** rotatent simultanément. Le notebook réunit les deux dé-biais étudiés isolément (décalage MGS-10, rotation MGS-12) dans le protocole composé canonique (`RotatedFitness(ShiftedFitness(inner, offset), M)`), confronte les 8 optimiseurs aux 4 variantes (plain / shifted / rotated / combined), et montre la thèse structurelle : **les biais isolés se composent** — mais l'effet du combined est *paysage-dépendant* (sub-additif sur Ackley pour WOA : la rotation masque le décalage ; super-additif sur Rosenbrock : les deux biais se renforcent), pas universellement pire. L'arc se ferme sur la *méthode* : un banc honnête rapporte ce qui aggrave **et** ce qui compense, et aucun optimiseur ne survit aux 4 variantes des 2 paysages — DE le plus robuste, WOA et Random à éviter. -- **Le démontage du recuit simulé : l'opérateur de Metropolis isolé** (MGS-19) — la thèse « composants > métaphores » éprouvée dans son sens le plus exigeant : non seulement on **reconstruit** un composé (MGS-5), mais on peut en **débrancher** un ingrédient et le rebrancher ailleurs. Le notebook isole `MetropolisReinsertion` du compound `SimulatedAnnealing` et l'injecte seul sur un GA de recombinaison (`ga.Reinsertion = reins`), à appariement constant avec un contrôle greedy pairwise. Verdict honnête **négatif** (G.9) : l'acceptation `exp(Δ/T)` détachée de la perturbation **n'aide pas** un GA à franchir les cols (sur Rastrigin/Ackley, tous les réglages Metropolis sous-performent le greedy, le plus chaud est le pire) — car l'enfant recombinant n'est pas un « voisin » du parent, donc accepter un moins bon enfant n'est quasiment que du bruit. Le bénéfice du recuit est dans le **couplage** perturbation+acceptation, pas dans l'acceptation seule. Démonter révèle la leçon finale : on PEUT décomposer un algorithme, l'opérateur isolé FONCTIONNE — mais le tout est plus que la somme de ses pièces, et c'est précisément en démontant qu'on le prouve. -- **La représentation au-dessus de l'algorithme** (MGS-21) — la question du No-Free-Lunch posée un niveau *au-dessus* du choix d'algorithme : à budget d'évaluations et fonction de coût égaux, un plan croisé 2×2 (représentation continue+arrondi vs permutations de lignes ; PSO vs GA) sur le Sudoku montre que le changement d'espace rapporte au PSO davantage que tout changement de moteur (−39 conflits contre −34,5), que seule la combinaison R2×GA résout (4/4 graines à 0 conflit, aucune cellule continue n'approchant la solution), et pourquoi : l'arrondi est une projection discontinue dont **100 % des candidats décodés** tombent hors de l'espace admissible. Avant de régler les paramètres d'un moteur, demander ce que le décodage détruit — la bonne réponse à un problème d'optimisation commence par la représentation, avant l'algorithme (MGS-16) et avant le paramètre (MGS-17). - -Le véritable enseignement rejoint celui des Parties 1-2 : aucune métaheuristique ne domine partout, et la bonne réponse à un problème d'optimisation est rarement « l'algorithme X » mais plutôt « **la bonne composition de primitives pour ce paysage de fitness** ». - -### Prochaines étapes - -- **Le code source de la bibliothèque** : le [fork jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — code source, tests unitaires, et feuille de route ([ROADMAP.md](https://github.com/jsboige/MetaGeneticSharp/blob/main/ROADMAP.md)) — prolonge cette partie vers une vraie bibliothèque industrialisable. Les notebooks ne sont que la vitrine pédagogique des briques qui y vivent. -- **Retour aux fondamentaux Python** : après avoir reconstruit WOA et EO à la main, reprendre [Search-11-Metaheuristics](../Part1-Foundations/Search-11-Metaheuristics.ipynb) (PSO, ABC, SA, BRO via `mealpy`) — l'appel de fonction y apparaît alors comme un *raccourci* au-dessus des mécanismes qu'on vient de reconstruire, et l'on mesure ce que la composition déclarative apporte. -- **Le pont vers l'ingénierie** : les patterns de composition (sous-populations spécialisées, migration, hybrides assemblés par grammaire fluente) existent dans la littérature mais sont rares dans les libs grand public — cette partie est le socle pour les implémenter en production sur un runtime .NET typé. -- **La série dans son ensemble** : le [sommaire Search](../README.md) cartographie les quatre parties — celle-ci est le side track C# .NET qui démontre que les concepts Python (Search-5 génétique, Search-11 métaheuristiques) se retrouvent, solidement typés et composables, dans un vrai moteur. - -### Le fil rouge - -Les métaheuristiques composables proposent un changement de regard sur l'optimisation : ne plus voir un algorithme bio-inspiré comme une **boîte noire** qu'on invoque (et dont on ignore le mécanisme caché derrière une métaphore animale), mais comme une **composition de primitives** qu'on peut intercepter, lire et recomposer. Reconstruire WOA ou Equilibrium Optimizer à partir de `Match`, `IfElse` et de croisements géométriques, c'est *démontrer* leur mécanisme plutôt que le postuler ; les confronter sur des benchmarks sans trier les victoires (divergence sur Schwefel), c'est éprouver le No-Free-Lunch au lieu de le réciter ; appliquer la même grammaire à un TSP combinatoire puis à un relief terrestre réel, c'est prouver l'agnosticisme de la représentation. La leçon transversale : la puissance d'une métaheuristique ne réside pas dans sa métaphore (baleine, équilibre, essaim) mais dans les **briques réutilisables** qu'elle assemble — et les composer soi-même est précisément ce qui transforme un utilisateur de bibliothèque en praticien capable d'inventer la configuration adaptée à un paysage de fitness donné. - -## Liens - -- [Fork jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — code source, tests, ROADMAP -- [GeneticSharp PR #87](https://github.com/giacomelli/GeneticSharp/pull/87) — origine du projet (couche métaheuristiques 2020-2022) -- [Search-11-Metaheuristics](../Part1-Foundations/Search-11-Metaheuristics.ipynb) — introduction Python (PSO, ABC, SA, BRO) et benchmarks comparatifs -- [Série Search](../README.md) — vue d'ensemble +# Partie 4 : Metaheuristiques Composables (MetaGeneticSharp) + +[↑ Série Search](../README.md) | [← Partie 3 : Recherche avancée](../Part3-Advanced/README.md) | [Notebooks MGS →](MGS-1-Introduction.ipynb) + +Comment passer de l'application *d'une* métaheuristique à la **composition** de plusieurs ? Cette partie ouvre la voie à [MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — une bibliothèque .NET qui reconstruit les métaheuristiques publiées (Whale Optimization, Equilibrium Optimizer, Differential Evolution, Bare-Bones PSO, modèle insulaire...) à partir de **primitives réutilisables** plutôt que comme des monolithes opaques. Trente-cinq notebooks .NET Interactive (C#) en sont le fil conducteur : un algorithme doit pouvoir s'énoncer en quelques lignes déclaratives, et chaque brique (sélection, croisement, mutation, réinsertion) doit pouvoir être interceptée et recomposée. + +L'arc part de la grammaire fluente (composition, MGS-1..5), caractérise les biais de l'optimiseur (centrage MGS-10, rotation MGS-12, synergie d'îles MGS-11/14), puis culmine sur le **No-Free-Lunch** : quatre capstones réunissent ses réponses classiques — mesurer le paysage (MGS-15), sélectionner l'algorithme (MGS-16), contrôler le paramètre pendant la course (MGS-17), éprouver le tout sur le banc CEC standard shift+rotate combiné (MGS-18) — avant un **démontage** : MGS-19 débranche l'opérateur de recuit du compound SA et l'éprouve isolé, montrant qu'un composant *fonctionne* détaché mais ne porte pas seul le bénéfice du tout ; puis une **inversion de la question** : MGS-21 croise représentation × algorithme sur le Sudoku et mesure que le choix de l'espace de recherche peut peser plus que le choix du moteur ; enfin une **confrontation externe systématique** : les dix notebooks MGS-22 à MGS-31 (campagne **[MGS vs mealpy](MGS-vs-mealpy/README.md)**) opposent la bibliothèque à mealpy 3.0.2 (Python/NumPy) sur un protocole apparié dans une seule exécution kernel .NET — ex æquo ou séparation totale selon la paire, fitness C# 5,72× plus rapide engloutie par la mécanique moteur, et le verdict final (MGS-31) tranche en deux axes que chaque paire mêlait : **coût systématique** (mealpy plus cher par évaluation 8/9) vs **qualité spécifique** (mealpy 6/9, MGS 3/9, écarts −6,5 à +17 conflits médians). + +Et cette composition se *voit* : avant de choisir un algorithme, MGS-8 rend le paysage de fitness en vraie heatmap graphique — chaque pixel coloré selon sa valeur de fitness, l'optimum global marqué en clair. + +[![Paysage de fitness analytique : heatmap de la fonction Sphere, l'optimum global au centre](assets/readme/mgs8-landscape.png)](MGS-8-LandscapeExplorer.ipynb) + +Contrairement aux Parties 1 et 2 (notebooks Python avec OR-Tools, DEAP, mealpy), cette partie est un **side track C# .NET 9.0** : elle consomme GeneticSharp et la couche métaheuristique comme sous-modules, et s'exécute via le kernel `dotnet-interactive`. C'est le pont entre la série pédagogique Python et une vraie bibliothèque de code industrialisable — la démonstration que les concepts vus en Python (Search-5 génétique, Search-11 métaheuristiques) se retrouvent, solidement typés et composables, dans un runtime .NET. Les notebooks consomment la bibliothèque (sous-module voisin [`MetaGeneticSharp/`](../MetaGeneticSharp/)) via ses DLLs buildées. + +## Pourquoi cette partie + +Les Parties 1-2 enseignent à *choisir* une métaheuristique face à un problème ; cette partie enseigne à en *construire* et en *combiner*. La motivation est double : + +- **Pédagogique.** Reconstruire WOA ou EO à partir de primitives (`Match`, `Container`, `Scoped`, contrôle-flux géométrique) force à comprendre *pourquoi* chaque étape existe — là où importer `mealpy` ou `scipy` masque le mécanisme derrière un appel de fonction. C'est le même réflexe qu'écrire un A* à la main avant d'utiliser `networkx`. +- **Ingénierie.** La composition ouvre des configurations qu'aucune bibliothèque monolithique n'offre directement : sous-populations spécialisées (Eukaryote), migration entre îles (Islands), métaheuristiques hybrides assemblées par grammaire fluente. Ces patterns existent dans la littérature mais sont rares dans les libs grand public. + +L'enseignement transversal rejoint celui des Parties 1-2 : aucune métaheuristique ne domine partout (cf [Search-11](../Part1-Foundations/Search-11-Metaheuristics.ipynb)), et la bonne réponse à un problème d'optimisation est rarement « l'algorithme X » mais plutôt « la bonne composition de primitives pour ce paysage de fitness ». + +## Positionnement : MetaGeneticSharp dans le paysage + +| Bibliothèque | Langage | Représentation | Philosophie | Lien | +|--------------|---------|----------------|-------------|------| +| **MetaGeneticSharp** | C# .NET 9 | Agnostique (gènes = interfaces GeneticSharp) | **Composants > métaphores** : algorithmes reconstruits depuis des primitives composables | [jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) | +| GeneticSharp | C# .NET | Agnostique (bit, permutation, arbre, float) | Bibliothèque GA classique, opérateurs en interfaces | [giacomelli/GeneticSharp](https://github.com/giacomelli/GeneticSharp) (sous-module, v3.1.4-9 / upstream master 4406ad7, non patché) | +| mealpy | Python | Vecteurs (continus surtout) | Catalogue large, tronc commun vectoriel, très compact | [thieu1995/mealpy](https://github.com/thieu1995/mealpy) | +| HeuristicLab | C# .NET | Plugin-based, GUI lourde | Plateforme d'expérimentation, optimisation interactive | [heal-research/HeuristicLab](https://github.com/heal-research/HeuristicLab) | + +MetaGeneticSharp vise le point que les autres n'occupent pas : **l'expressivité déclarative de mealpy** (un algorithme en quelques lignes) **sur la représentation agnostique de GeneticSharp** (bit strings, permutations, arbres), sans sacrifier la performance. C'est le « child project » que [GeneticSharp PR #87](https://github.com/giacomelli/GeneticSharp/pull/87) suggérait de devenir : la couche métaheuristiques du PR, absorbée dans un moteur autonome au-dessus d'un GeneticSharp vanilla. + +## Objectifs d'apprentissage + +À l'issue de cette partie, vous serez capable de : + +1. **Reconstruire** une métaheuristique publiée (WOA, EO) à partir de primitives composables plutôt que d'en importer une boîte noire +2. **Composer** des métaheuristiques via la grammaire fluente (`Match`, `Container`, `Scoped`) pour assembler des configurations hybrides +3. **Structurer** une population en sous-populations spécialisées (Eukaryote) ou en îles migratoires (Islands) +4. **Évaluer** quand une composition custom bat une métaheuristique monolithique sur un paysage de fitness donné + +## Notebooks + +Cette partie se compose de trente-cinq notebooks .NET Interactive (C#), hébergés dans ce répertoire et consommant le sous-module voisin [`MetaGeneticSharp/`](../MetaGeneticSharp/) : + +| # | Notebook | Concept clé | Primitives introduites | Durée | +|---|----------|-------------|------------------------|-------| +| 1 | [MGS-1-Introduction](MGS-1-Introduction.ipynb) | Moteur autonome `MetaGeneticAlgorithm` | `DefaultMetaHeuristic`, `NoOp`, fitness quadratique | ~40 min | +| 2 | [MGS-2-Composition](MGS-2-Composition.ipynb) | Assemblage déclaratif | `Match`, contrôle-flux, grammaire fluente | ~45 min | +| 3 | [MGS-3-Eukaryote](MGS-3-Eukaryote.ipynb) | Sous-populations spécialisées | chromosomes composites, partitionnement | ~50 min | +| 4 | [MGS-4-Islands](MGS-4-Islands.ipynb) | Modèle insulaire | populations structurées, migration entre îles | ~50 min | +| 5 | [MGS-5-CompoundMetaheuristics](MGS-5-CompoundMetaheuristics.ipynb) | Reconstruire les composés publiés (WOA/EO/FBI) | `MetaHeuristicsService`, `WhaleOptimisationAlgorithm`, `EquilibriumOptimizer`, factory `CreateMetaHeuristicByName` | ~50 min | +| 6 | [MGS-6-Benchmarks](MGS-6-Benchmarks.ipynb) | Comparaison honnête | `KnownFunctions`, composé WOA vs Uniform vs Islands | ~50 min | +| 7 | [MGS-7-TSP](MGS-7-TSP.ipynb) | Grammaire agnostique à la représentation | `TspFitness`, `OrderedCrossover`, permutation + `Islands` | ~45 min | +| 7b | [MGS-7b-LandscapeMultidim](MGS-7b-LandscapeMultidim.ipynb) | Projection N-D des paysages (voir en dimension ≥ 5) | surcharge `RenderHeatmap` N-D de `KnownFunctionLandscape`, projection MAX sur les coordonnées cachées (opérateur Gtk# verbatim) ; Sphere 2-D vs 5-D, Rastrigin n=2/5/10/30, Schwefel n=5/30 | ~30 min | +| 7c | [MGS-7c-RosenbrockGriewank](MGS-7c-RosenbrockGriewank.ipynb) | Projection N-D : Rosenbrock (vallée banane) + Griewank (produit-cosinus) | `RosenbrockFitness`, `GriewankFitness` sur la surcharge N-D de `RenderHeatmap` ; dims $n=2/5/30$ ; la vallée étroite de Rosenbrock (largeur $\sim 10^{-2}$) disparaît en MAX-projection 30-D, Griewank produit-cosinus $\prod \cos(x_i/\sqrt{i})$ vs Ackley somme-cosinus | ~30 min | +| 7d | [MGS-7d-MichalewiczDixonPrice](MGS-7d-MichalewiczDixonPrice.ipynb) | Projection N-D : Michalewicz (crêtes raides) + Dixon-Price (vallée non-scalable) | `MichalewiczFitness` (paramètre $m=10$), `DixonPriceFitness` sur la surcharge N-D de `RenderHeatmap` ; dims $n=2/5/30$ ; crêtes quasi-binaires de Michalewicz ($m=10$ sature l'amplitude), vallée parabolique-croisée non-rectiligne de Dixon-Price | ~30 min | +| 8 | [MGS-8-LandscapeExplorer](MGS-8-LandscapeExplorer.ipynb) | Visualiser la surface de fitness | heatmaps PNG graphiques, 3 modes (fonction / carte d'altitude / image), trajectoire de convergence | ~50 min | +| 9 | [MGS-9-EverestRelief](MGS-9-EverestRelief.ipynb) | Relief terrestre réel comme paysage | `DemGrid` (wrapper `ImageHeightMapFunction`), cartes `KnownHeightMap` de jsboige, GA/WOA/EO vs PSO, flipbook de convergence | ~55 min | +| 10 | [MGS-10-CenterBias](MGS-10-CenterBias.ipynb) | Biais central vs robustesse au déplacement | banc `CenterBiasBenchmark` (Kudela 2022), composés WOA/EO/FBI/DE/BBPSO/SA vs GA/Random, signature $\Delta$ | ~45 min | +| 11 | [MGS-11-IslandSynergy](MGS-11-IslandSynergy.ipynb) | Synergie d'îles complémentaires (verdict mesuré) | `IslandCompoundMetaheuristic`, archipel hétérogène DE+BBPSO, dé-biais `ShiftedFitness`, GIF multicolore par île | ~45 min | +| 12 | [MGS-12-AxisAlignment](MGS-12-AxisAlignment.ipynb) | Biais d'alignement d'axes (rotation) | décorateur `RotatedFitness` ($M x$, Givens orthogonale), séparabilité vs rotation, optimum relocalisé, signature $\Delta$ | ~45 min | +| 13 | [MGS-13-LandscapeDebias](MGS-13-LandscapeDebias.ipynb) | Pourquoi la rotation casse la séparabilité (visuel) | heatmaps 2-D des fonctions dé-biaisées `ShiftedFitness`/`RotatedFitness`, Sphere invariante vs Rosenbrock/Rastrigin rotatées, composition CEC | ~40 min | +| 14 | [MGS-14-IslandSynergyFound](MGS-14-IslandSynergyFound.ipynb) | Une synergie d'îles *trouvée* (et un cas négatif) | archipel `DE+BB-3:1` (3 îles DE + 1 île BBPSO), migration douce, banc multi-seed à contrôle propre, synergie robuste sur Ackley / absente sur Rastrigin | ~45 min | +| 15 | [MGS-15-LandscapeAnalysis](MGS-15-LandscapeAnalysis.ipynb) | Le *nombre* derrière la heatmap — FDC globale + rugosité locale | deux métriques complémentaires : FDC (Jones & Forrest 1995, Pearson fitness–distance, nuage SVG inline) + autocorrélation de marche aléatoire (Weinberger 1990, longueur de corrélation) + neutralité ; Sphere FDC 0,97 & lisse vs Rastrigin FDC 0,71 & rugueux (L≈1 pas) | ~40 min | +| 16 | [MGS-16-AlgorithmSelection](MGS-16-AlgorithmSelection.ipynb) | **Capstone** — sélectionner le bon optimiseur selon le paysage (Rice 1976) | No-Free-Lunch (Wolpert & Macready 1997) + cadre de Rice (features → portfolio → performance) ; réutilise les 8 optimiseurs de MGS-10 et les features FDC/ρ₁/neutralité de MGS-15 ; sélecteur heuristique validé puis testé sur un 4ᵉ paysage inconnu (Rosenbrock) | ~70 min | +| 17 | [MGS-17-ParameterControl](MGS-17-ParameterControl.ipynb) | **Deuxième réponse au No-Free-Lunch** — adapter les paramètres pendant la course (Eiben 1999) | taxonomie Eiben (tuning vs control : déterministe / adaptatif / self-adaptatif) via le vrai moteur du fork `ProbabilityConfig.DynamicProbability` ; schedule de décroissance, contrôle adaptatif par diversité, self-adaptatif hétérogène ; No-Free-Lunch au niveau du *paramètre* (l'ordre s'inverse entre Rastrigin et Sphere) | ~50 min | +| 17b | [MGS-17b-Empirical-Algorithm-Selection](MGS-17b-Empirical-Algorithm-Selection.ipynb) | **Distillation Theodore Deguest L4 EPITA SCIA 2026** — squelette : cadre theorique (Rice 1976, Wolpert 1996, Smith-Miles 2009) + setup env execute | introduction, attribution, plan en 4 tranches (cadre / protocole 3 terrains / Pareto+discriminant / ponts series) ; noyau execute via kernel `coursia-ml-training` ; PR Theodore Deguest [jsboigeEpita/2026-Epita-Intelligence-Symbolique#42](https://github.com/jsboigeEpita/2026-Epita-Intelligence-Symbolique/pull/42) | ~30 min (tranches 1+2+3 livrees ; tranche 4 benchmarks reels Theodore par ai-01 ou lane GPU) | +| 18 | [MGS-18-CecBanc](MGS-18-CecBanc.ipynb) | **Consolidation du banc CEC** — shift+rotate combinés (le protocole standard de dé-biais) | décorateurs composés `RotatedFitness(ShiftedFitness(inner, offset), M)` (Givens orthogonale) ; banc à 4 variantes (plain/shifted/rotated/combined), étend `CenterBiasBenchmark` ; 8 optimiseurs sous shift+rotate sur Ackley+Rosenbrock ; les biais isolés (WOA central MGS-10, GA axe MGS-12) se composent — effet sub-additif ou super-additif selon le paysage | ~50 min | +| 19 | [MGS-19-MetropolisReinsertion](MGS-19-MetropolisReinsertion.ipynb) | **Recuit simulé décomposé** — l'opérateur de Metropolis débranché de SA et greffé seul sur un GA | `MetropolisReinsertion` isolé du compound `SimulatedAnnealing` et injecté via `MetaGeneticAlgorithm.Reinsertion` ; banc 5 configs (pairwise greedy contrôle, 3 températures Metropolis, élitiste référence) sur Sphere/Rastrigin/Ackley + limite frozen ; verdict honnête **négatif** — l'acceptation `exp(Δ/T)` détachée du couplage perturbation+acceptation ne porte pas le bénéfice du recuit | ~45 min | +| 21 | [MGS-21-Representation-vs-Algorithme](MGS-21-Representation-vs-Algorithme.ipynb) | **Représentation × algorithme : le plan croisé Sudoku** — quel facteur pèse le plus ? | deux représentations (R1 vecteur continu + décodage arrondi, R2 grille à permutations de lignes via l'algèbre de swaps) × deux moteurs (PSO composé, GA permutation), budget ~8 000 évaluations, 4 graines {0,1,7,42}, critère de verdict pré-enregistré ; verdict en deux temps — la représentation domine la colonne PSO (−39 conflits vs −34,5/−6 pour l'algorithme), comparable sur la colonne GA ; 4/4 résolutions en R2/GA, aucune en R1 ; cause mesurée : 100 % des candidats R1 décodés tombent hors de l'espace admissible | ~40 min | +| 22 → 31 | [Campagne **MGS vs mealpy**](MGS-vs-mealpy/README.md) — **10 notebooks** (PSO, DE, SA, WOA, EO, FBI, BBPSO, GA, Scatter Search, synthèse) | **Confrontation externe systématique** — la même expérience (protocole apparié Sudoku-Easy[0], budget ~8 000 évals, graines {0,1,7,42}, déterminisme 8/8 ou 12/12), deux bibliothèques (MGS C# .NET 9 vs mealpy 3.0.2 Python/NumPy via PythonNet dans le kernel .NET), un verdict quantitatif. Chaque paire isole un mécanisme (sélection greedy vs réinsertion de population, bruit A1 N(0,1) vs uniforme, écart d'ancrage, ablation de couche mémétique) et tranche sur la question « le moteur ou la stratégie ? » | voir [table des paires](MGS-vs-mealpy/README.md#table-des-paires) | + +Les 8 figures MGS-7b (heatmaps de la projection N-D des paysages Sphere/Rastrigin/Schwefel) sont cataloguées dans [`assets/readme/MANIFEST.md`](assets/readme/MANIFEST.md) avec leurs **descriptions visuelles** verbatim (audit vision MiniMax M3 c.755, doctrine #5780) — voir notamment la note disclosed sur la convergence visuelle des heatmaps Rastrigin-d2/d10/d30 en projection MAX (moyennes RGB identiques à 2 décimales près). + +### Applications spécialisées + +Les notebooks d'application GA (détection de bords, optimisation de portefeuille — variants PyGAD Python et GeneticSharp C#) sont rassemblés dans la section [`Applications/Hybrid/`](../Applications/README.md) : **App-9 / App-9b** (EdgeDetection) et **App-10 / App-10b** (Portfolio). La série MGS numérotée (MGS-1 à MGS-19, MGS-21, plus la trilogie de ponts MGS-7b/7c/7d de projection N-D ; MGS-20, langage de composition, est en préparation) constitue le cœur propre à la Partie 4. La **campagne MGS vs mealpy** (MGS-22 à MGS-31, 10 notebooks comparatifs) vit dans la sous-série dédiée [`MGS-vs-mealpy/`](MGS-vs-mealpy/README.md), avec son sommaire, son protocole commun et sa synthèse croisée. + +La série suit un fil continu plutôt qu'un catalogue : on **reconstruit** les composés publiés depuis leurs primitives (MGS-5), on les **confronte** honnêtement (MGS-6, MGS-7), puis on apprend à *voir* le paysage (MGS-8, MGS-9), à *mesurer* ses biais (MGS-10 à MGS-14), à le *quantifier* (MGS-15), à *raisonner* sur le choix de l'algorithme (MGS-16), de ses paramètres (MGS-17), du protocole d'évaluation (MGS-18), la démontabilité d'un composé (MGS-19) — et enfin à *questionner la représentation elle-même* (MGS-21 : le croisement représentation × algorithme montre que le choix de l'espace peut dominer le choix du moteur). Le déroulé notebook par notebook figure dans le « Parcours détaillé » plus bas, et la Conclusion reprend les enseignements transversaux. Feuille de route du fork : [ROADMAP.md](https://github.com/jsboige/MetaGeneticSharp/blob/main/ROADMAP.md). + +L'arc se résume en onze vagues conceptuelles, chacune posant la brique que la suivante compose : + +```mermaid +flowchart LR + W1["Socle & composition
MGS-1 — Moteur autonome
MGS-2 — Grammaire fluente
(Match, Container, Scoped)"] + W2["Structuration de population
MGS-3 — Eukaryote
(sous-populations)
MGS-4 — Islands (migration)"] + W3["Composés publiés & confrontation
MGS-5 — Reconstruire WOA/EO/FBI
MGS-6 — Benchmarks
(No-Free-Lunch)
MGS-7 — TSP combinatoire"] + W4["Paysages de fitness
MGS-7b/7c/7d — Projection N-D
MGS-8 — Landscape Explorer
MGS-9 — Everest (relief réel)"] + W5["Biais & mesure falsifiable
MGS-10 — Biais central
(Kudela 2022)
MGS-11 — Synergie d'îles
(verdict négatif)"] + W6["Rotation & retour critique
MGS-12 — Alignement d'axes
MGS-13 — Paysages dé-biaisés
MGS-14 — Synergie conditionnelle"] + W7["Nombre & sélection (capstone)
MGS-15 — Métriques de paysage
(FDC, autocorrélation)
MGS-16 — Sélection d'algorithme
(Rice 1976, No-Free-Lunch)"] + W8["Contrôle du paramètre
MGS-17 — Parameter Control
(Eiben 1999)
tuning vs control
(déterministe / adaptatif / self-adaptatif)"] + W9["Banc CEC consolidé
MGS-18 — shift + rotate combinés
(protocole CEC)
biais composés
(sub- vs super-additif)"] + W10["Recuit démonté
MGS-19 — Metropolis isolé
du compound SA
opérateur fonctionnel
bénéfice = couplage"] + W11["Représentation vs algorithme
MGS-21 — plan croisé Sudoku
R1 continue+arrondi vs
R2 permutations
l'espace peut dominer le moteur"] + W1 --> W2 --> W3 --> W4 --> W5 --> W6 --> W7 --> W8 --> W9 --> W10 --> W11 +``` + +## Configuration requise + +Le kernel `dotnet-interactive` installé (**1.0.707101**, hôte .NET moderne) **charge nativement les assemblies `net9.0`** — vérifié par exécution : MGS-6 (qui référence `MetaGeneticSharp.Extensions` net9.0), MGS-18, MGS-19 et MGS-21 s'exécutent verts sur ce kernel. Les notebooks MGS se répartissent sur deux TFM : + +- **MGS-1 à MGS-5** (Introduction, Composition, Eukaryote, Islands, Compound) ne consomment que `MetaGeneticSharp.Domain` + `Infrastructure` + `GeneticSharp`. Ils référencent les **DLL `net8.0`**, chargées par rétro-compat sur le kernel actuel (qui supporte net8.0/net9.0/net10). +- **MGS-6 à MGS-9** (Benchmarks, TSP, Landscape, Everest) dépendent en plus de `MetaGeneticSharp.Extensions` (SkiaSharp / `System.Drawing.Common`). Ils référencent les DLL `net9.0` et **s'exécutent sur le kernel actuel** (MGS-6 vérifié vert). *Sur l'ancien kernel 1.0.552801 (hôte net8.0-only), ils restaient bloqués* (follow-up historique désormais non requis sur le kernel actuel). + +Règle : pas de contournement, installer l'environnement complet : + +```powershell +# 1. .NET SDK (9.0 requis pour le fork source ; 8.0/10.0 optionnels) +dotnet --version + +# 2. dotnet-interactive (kernel Jupyter pour C#, hôte .NET moderne >= 1.0.707101) +dotnet tool install --global Microsoft.dotnet-interactive +dotnet interactive jupyter install + +# 3. Sous-modules + build du fork (les notebooks chargent les DLL par #r absolu) +cd MyIA.AI.Notebooks/Search/MetaGeneticSharp +git submodule update --init --recursive +dotnet build # build net9.0 (fork source ; DLLs pour MGS-6..18) +``` + +> **Bins `net8.0` pour MGS-1..5.** Le fork est actuellement single-TFM `net9.0`, donc `-p:TargetFramework=net8.0` échoue (le `project.assets.json` restauré ne contient que la cible net9.0). Pour produire `Domain` + `Infrastructure` en `net8.0` (référencés par MGS-1..5, chargés par rétro-compat sur le kernel actuel), il faut soit retargeter temporairement le `.csproj` en `net8.0` puis `dotnet build`, soit — solution propre — multi-targeter le fork en `net8.0;net9.0` (follow-up sur le fork, `Extensions`/SkiaSharp restant net9.0-only). Les bins référencés par MGS-1..5 doivent exister sous `src/MetaGeneticSharp.Domain/bin/Debug/net8.0/`. + +Les notebooks chargent les DLL via `#r "c:/dev/MetaGeneticSharp/..."` (chemin du checkout de travail du fork). **MGS-1..5** pointent sur `src/MetaGeneticSharp.Domain/bin/Debug/net8.0/` (4 DLL : GeneticSharp.Domain, GeneticSharp.Infrastructure.Framework, MetaGeneticSharp.Domain, MetaGeneticSharp.Infrastructure) ; **MGS-6..14** pointent sur `src/MetaGeneticSharp.Extensions/bin/Debug/net9.0/` (Extensions + SkiaSharp + System.Drawing.Common) ; **MGS-21..28** pointent sur `src/MetaGeneticSharp.Domain/bin/Debug/net9.0/` (GeneticSharp.Infrastructure.Framework + MetaGeneticSharp.Infrastructure + MetaGeneticSharp.Domain, chemins relatifs `../MetaGeneticSharp/...`). + +**Reproductibilité.** Les résultats numériques de MGS-1 à MGS-9 sont **stochastiques** (le RNG du framework n'y est pas seedé) : les outputs committés sont une exécution valide, les valeurs varient d'une exécution à l'autre. À partir de MGS-10, les bancs sont seedés pour devenir **reproduisibles** : + +| Notebook | Strategy | Verdict | +|----------|----------|---------| +| **MGS-10** | `ResetSeed(masterSeed)` une fois avant la suite | reproduisible (biais central) | +| **MGS-11** | `ResetSeed(42)` avant chaque banc | reproductible (caveat : graine unique, pas multi-graines) | +| **MGS-12** | reseed avant chaque paire optimiseur | reproductible (caveat : dim 2, budget large → $\Delta \approx 0$ pour tous ; cf exercice 2) | +| **MGS-14** | multi-seed (5 graines) avant chaque archipel | reproduisible (synergie robuste sur Ackley, absente sur Rastrigin) | +| **MGS-17** | multi-seed (5 graines {7,42,99,123,777}) | reproduisible (`DynamicProbability` déterministe, pas de RNG interne) | +| **MGS-19** | multi-seed (3 graines {7,42,99}) avant chaque course | reproduisible (banc Metropolis-vs-Pairwise + limite frozen) | +| **MGS-21** | multi-seed (4 graines {0,1,7,42}) par cellule du plan croisé, `FastRandomRandomization.ResetSeed(seed)` avant création de population | reproduisible (croisement 2×2, 4/4 résolutions en R2/GA, déterminisme vérifié sur 3 exécutions) | + +Règle C.2 : les notebooks sont committés **avec leurs outputs** (exécution réelle, kernel .NET). + +## Parcours détaillé + +### 1 — Introduction + +Pourquoi un moteur autonome au-dessus de GeneticSharp ? Le notebook pose le contrat : un `MetaGeneticAlgorithm` qui pilote l'évolution sans dépendre de la classe `GeneticAlgorithm` amont, et un `IMetaHeuristic` qui intercepte chaque étape. On compare `DefaultMetaHeuristic` (reproduit le comportement GA classique) à `NoOp` (ne fait rien — l'observateur passif) sur un fitness quadratique simple. C'est le socle : tout le reste de la série compose au-dessus de ce moteur. + +### 2 — Composition + +Le cœur de la thèse « composants > métaphores ». On introduit `Match` (dispatch déclaratif sur le contexte d'évolution) et les primitives de contrôle-flux, puis on assemble une métaheuristique en quelques lignes lisibles. Ce notebook établit la grammaire fluente (`Match`, `Container`, `Scoped`) que WOA et EO réutiliseront plus tard comme briques plutôt que comme monolithes. + +### 3 — Eukaryote + +On cesse de traiter la population comme un sac homogène. Le modèle eucaryote partitionne la population en sous-populations spécialisées portées par des chromosomes composites — chaque compartiment peut avoir sa propre métaheuristique. C'est une configuration qu'aucune bibliothèque monolithique grand public n'offre directement, et qui devient naturelle une fois la composition maîtrisée. + +### 4 — Islands + +Le modèle insulaire structure la population en îles migratoires : chaque île évolue indépendamment, puis des individus migrent périodiquement. La primitive `IslandMetaHeuristic` assemble ce schéma à partir des mêmes briques que les notebooks précédents. La leçon : la diversité structurée (vs une population panmictique) change la dynamique de convergence. + +### 5 — Métaheuristiques composées + +D'où viennent les algorithmes « publiés » — Whale Optimization (WOA), Equilibrium Optimizer (EO), Forensic-Based Investigation (FBI) — et comment les utiliser sans retomber dans le piège de la boîte noire ? Ce notebook montre, pour chaque composé du catalogue, le même parcours en trois temps : **(1) la description** — la métaphore et la mécanique, dans l'esprit des fiches de `mealpy` ; **(2) la reconstruction depuis les primitives** — le corps réel de la méthode `BuildMainHeuristic()` qui assemble l'algorithme à partir de briques (`IfElse`, `Match`, `GenerationMetaHeuristic`, croisements géométriques), lu transparentement ; **(3) le raccourci factory** — le one-liner `MetaHeuristicsService.CreateMetaHeuristicByName("...")` qui produit *exactement* cette reconstruction, avec la preuve (le type racine renvoyé) que raccourci et reconstruction sont identiques. C'est l'argument « composants > métaphores » poussé jusqu'à la **preuve d'équivalence** : reconstruire un algorithme bio-inspiré *démontre* son mécanisme au lieu de le cacher derrière une métaphore animale (critique de Sørensen, 2015). Les benchmarks de MGS-6 mettent ensuite ces composés à l'épreuve. + +### 6 — Benchmarks + +La confrontation honnête. Dix fonctions standard (`KnownFunctions.cs` : Sphere, Rastrigin, Rosenbrock, Ackley, Griewank, Schwefel, Michalewicz, Zakharov, Booth, Dixon-Price) servent de paysages de test. On compare trois configurations — Uniform, WOA-reconstruit-depuis-les-primitives, Islands — et on rapporte les résultats sans trier les victoires : WOA gagne ou égalise sur 7/10, **diverge sur Schwefel** (le contrôle-flux géométrique sans clamp de bornes explose sur [-500, 500]). Cette divergence n'est pas un bug caché : l'inspectabilité du composé (on lit l'`IfElse` du bubble-net) en fait une démonstration de No-Free-Lunch, là où `mealpy` masquerait le mécanisme. + +### 7 — TSP combinatoire + +La grammaire de composition est-elle agnostique à la représentation ? MGS-1 à 6 opèrent sur des surfaces *continues* (gènes en `double`), mais les primitives structurantes (`Match`, `Container`, `Scoped`, `Islands`) vivent *sous* la couche géométrique. Ce notebook applique la **même** `IslandMetaHeuristic` à un problème de **permutation** — le Voyageur de Commerce sur 20 villes, gènes = index entiers — **sans aucune adaptation** : le modèle insulaire opère sur `IChromosome` et ne lit jamais `Gene.Value`. La comparaison reste honnête (G.9) : la baseline panmictique bat les Islands sur cette instance TSP-20, illustration de No-Free-Lunch — le point n'est pas la victoire mais le **transfert sans réécriture** de la grammaire d'une géométrie continue à un espace combinatoire. Setup : `TspFitness`, `OrderedCrossover` (OX1), `ReverseSequenceMutation`. Au-delà des îles, ce notebook éprouve aussi la **théorie des croisements géométriques de Moraglio** (2007) — un crossover est *géométrique* si sa progéniture reste sur le segment géodésique entre les parents, pour une métrique donnée. Or une permutation admet **plusieurs métriques naturelles**, et le fork en câble deux : la distance de **swap** (Cayley : combien de transpositions séparent deux ordres), réalisée par `OrderedEmbedding` (Config 3), et la distance d'**insertion** (Ulam : combien d'éléments déplacer en décalant les autres), réalisée par `InsertionEmbedding` (Config 4). La Config 4 démontre le point central du *deep learning géométrique* : depuis le parent `[0,1,2,3,4]` vers une même cible-permutation `[2,0,1,3,4]`, un pas de swap atteint `[2,1,0,3,4]` là où un pas d'insertion atteint `[2,0,1,3,4]` — deux **géodésiques distinctes**, donc deux descendants distincts atteignables en un seul croisement. **C'est l'embedding (le choix de la métrique) qui porte la géométrie, pas le moteur** (`GeometricCrossover`) ni l'opérateur (le centroïde) : changer uniquement d'embedding change le paysage exploré. Cadrage honnête (G.9) : ni swap ni insertion n'a de privilège géographique sur ce TSP (ce sont des distances sur les étiquettes d'indice, pas sur les coordonnées des villes) — les deux sont des baselines, et le centroïde naïf à deux parents borne symétriquement les deux métriques (limite déjà documentée en Config 3) ; un embedding appris équivariant par permutation ferait mieux que les deux. + +### 7b — Projection N-D des paysages + +MGS-6 a présenté les dix fonctions canoniques en 2-D. Mais une **vraie métaheuristique** optimise dans des dimensions bien supérieures (Rastrigin est intéressant à $n=30$, Schwefel a un optimum trompeur en $n \geq 10$). Ce notebook pont active la **surcharge N-D** de `KnownFunctionLandscape.RenderHeatmap` — la même rampe de couleurs, la même `SkiaLandscapeRenderer`, mais sur une dimension arbitraire : pour chaque pixel du canvas 2-D, `nbSamples` tirages uniformes des coordonnées cachées $x_2 \dots x_{N-1}$ et on garde le **MAX** (l'opérateur verbatim du contrôleur Gtk# original de jsboige). La projection rend lisibles des phénomènes invisibles en 2-D : la **Sphere** 5-D garde $(0,0)$ comme candidat d'optimum mais le MAX sur les coordonnées cachées fait émerger d'autres pixels ; **Rastrigin** en $n=2/5/10/30$ montre la densité de minima locaux croître avec la dimension (la heatmap rougit) ; **Schwefel** en $n=5/30$ fait émerger le *vrai* optimum global, loin du centre, dès qu'on autorise les coordonnées cachées à varier. C'est le pont entre la visualisation 2-D de MGS-6/MGS-8 et la réalité haute-dimension où vit l'optimisation — et le terrain où la projection N-D (capacité distinctive du renderer fork) est *nécessaire*, pas optionnelle. + +### 7c — Projection N-D : Rosenbrock (vallée banane) et Griewank (produit-cosinus) + +MGS-7b a projeté les quatre fonctions les plus classiques (Sphere, Rastrigin, Schwefel, Ackley). Ce second notebook pont poursuit l'exploration en haute dimension avec deux fonctions au comportement **structurellement différent** : **Rosenbrock** — la *vallée-courbe-étroite banane* — dont l'optimum serpente le long de la diagonale $x_i \approx 1$, et **Griewank**, dont le terme cosinus est un **produit** $\prod \cos(x_i/\sqrt{i})$ (et non une somme comme Ackley), générant en 2-D des bandes ondulantes perpendiculaires. La projection N-D $n=2/5/30$ révèle deux phénomènes que la 2-D masque : la vallée de Rosenbrock, **étroite** (largeur $\sim 10^{-2}$), devient quasi-invisible en 30-D (la probabilité qu'un tirage tombe *dans* la vallée est faible, la MAX-projection retient donc presque toujours une fitness hors vallée) ; Griewank, lui, voit son produit de 30 cosinus s'effondrer vers une surface lisse (le produit de nombreux termes $<1$ décroît vite). Deux leçons géométriques qui justifient la projection N-D : la dimension change la *visibilité* d'une structure fine, et produit vs somme ne se projettent pas pareil. + +### 7d — Projection N-D : Michalewicz (crêtes raides) et Dixon-Price (vallée non-scalable) + +Le troisième notebook pont referme la trilogie sur les deux dernières fonctions canoniques au comportement discriminant : **Michalewicz** — dont le paramètre $m=10$ dans $\sin^{2m}(\cdot)$ sature l'amplitude entre 0 et 1, créant des **crêtes quasi-binaires** alternant bandes sombres et claires (et dont l'optimum *dépend de la dimension* $n$, propriété rare) — et **Dixon-Price**, dont la vallée étroite est **parabolique-croisée** (le couplage $2(2x_2^2 - x_1)^2$ impose que $x_2$ suive $x_1$ selon une racine, pas selon $x_1^2$ comme Rosenbrock), donc **non-rectiligne** : étroite en haut, elle s'évase en bas. En projection N-D $n=2/5/30$, le paramètre $m=10$ rend chaque dimension presque discontinue (la MAX-projection retient les crêtes les plus marquées), et le couplage cross-dimension de Dixon-Price défait toute lecture coordonnée-par-coordonnée. La trilogie MGS-7b/7c/7d couvre ainsi les **huit fonctions canoniques** du banc en projection N-D — le terrain complet où la dimension révèle ce que la 2-D dissimule. + +### 8 — Fitness Landscape Explorer + +Tant que la surface de recherche est invisible, le choix d'une métaheuristique relève du doctrinal ; la visualiser le rend éclairé. Ce notebook consomme la bibliothèque `LandscapeRenderer` du fork — récupérée **byte-exact** depuis le *Landscape Explorer* original de jsboige (branche Metaheuristics @ `d05826fd`, PR giacomelli/GeneticSharp#87) — pour produire de **vraies heatmaps PNG graphiques** : `RenderHeatmap` peint chaque pixel selon la valeur de fitness (rampe rouge = haut / cyan = bas, minimum global Blanc, maximum global Noir) et `Plot` superpose les individus (BlueViolet) et le meilleur (Aqua). Trois modes de paysage sont couverts : **(1) fonction analytique** (les **vraies** `KnownFunctions`, p. ex. Sphere), **(2) carte d'altitude** — les **quatre cartes originales de jsboige** (Everest, Népal-Bhoutan, Plateau tibétain, Monde), récupérées byte-exact et embarquées comme ressources, lues comme champs de fitness via la verbatim `ImageHeightMapFunction` — et **(3) image custom** (un bitmap bimodal synthétique). La trajectoire de convergence du GA se superpose à la heatmap. Un wrapper `ShiftedFitness` translate l'optimum hors du centre pour rendre le **center-bias** visible : le GA converge sur l'optimum déplacé (≈ (2, 2)), preuve d'une recherche authentique. Les PNG sont encodés en base64 et affichés via `display(HTML(...))` — fiable sous papermill .NET (références DLL locales du fork, pas de `#r "nuget:"`). + +[![Convergence du GA sur Rastrigin multimodal (flipbook animé GIF89a, 7 frames × 400 ms ≈ 2.8 s) : le nuage de population BlueViolet se contracte génération après génération, depuis une large dispersion (frame 1, ~50 points répartis sur toute la grille) jusqu'à un cluster compact au voisinage du minimum global (frame 7, ~30 points regroupés au centre). Le paysage de fond (Rastrigin multimodal) reste visible sur toutes les frames.](assets/readme/mgs8-convergence.gif)](MGS-8-LandscapeExplorer.ipynb) + +### 9 — Trouver l'Everest : relief réel + +L'aboutissement : le paysage n'est plus synthétique mais un **relief terrestre réel**, et en **vraie résolution**. Les quatre cartes d'altitude sont les **assets verbatim de jsboige** (`KnownHeightMap.{World, TibetanPlateau, NepalBhoutan, EverestMount}`, PNG ~2560 px, acquis à l'origine depuis un service d'élévation WMS) — récupérés **byte-exact** sur le fork @ `d05826fd` et lus par la classe verbatim `ImageHeightMapFunction` (niveaux de gris = altitude, interpolation inverse-distance). Pas de grille `int[]` rééchantillonnée, pas de downsampling ETOPO1 : le PNG haute-définition **est** le champ de fitness. La classe pédagogique `DemGrid` n'est qu'une enveloppe *drop-in* sur `ImageHeightMapFunction` (elle expose `Interp`/`GlobalMax`/`ElevMin`/`ElevMax`) ; aucune logique d'optimisation n'y vit. On **maximise** le niveau de gris — le pixel le plus clair est le sommet — sur quatre cartes à zoom croissant (Monde → Plateau → Himalaya → Everest : le pic se resserre à mesure qu'on zoome). On lance le moteur MGS (GA / WOA / Equilibrium Optimizer) plus une baseline **PSO** externe à budget d'évaluations égal, et on mesure le **taux de réussite** de chaque méthode à localiser le sommet, relié au rapport taille-du-bassin / résolution. Un **flipbook de convergence** (même orchestration `GenerationRan` qu'en MGS-8) montre ensuite la population se contracter génération après génération vers le sommet sur la région Everest. Rendu en **heatmaps PNG graphiques** via le même `SkiaLandscapeRenderer` du fork que MGS-8 (cohérence intra-série, rendu SkiaSharp cross-platform), avec la **cible inversée** : MGS-8 *minimise* ses fonctions analytiques (l'optimum porte le marqueur Blanc) ; MGS-9 *maximise* l'altitude, donc c'est le **sommet** qui porte le **marqueur Noir** — la cible explicite de la recherche. + +[![Relief terrestre réel comme paysage de fitness : carte d'altitude de l'Everest, le sommet (pixel le plus clair) est la cible](assets/readme/mgs9-everest.png)](MGS-9-EverestRelief.ipynb) + +### 10 — Biais central + +MGS-6 montrait qu'aucune métaheuristique publiée ne bat la composition en performance brute ; MGS-10 ajoute une **seconde preuve**, plus profonde, en mesurant un défaut que la performance masque : le **biais central**. Le notebook câble le banc `CenterBiasBenchmark` du fork (protocole *centré-vs-déplacé* de Kudela, 2022) : chaque optimiseur est lancé sur une même fonction (Sphere, Rastrigin, Ackley ; dimension 5, NFE = 5000) en deux versions, l'optimum au **centre** puis **relocalisé** hors centre via `ShiftedFitness`. La signature $\Delta = f^\star_{\text{déplacé}} - f^\star_{\text{centré}}$ révèle si l'optimiseur résout la fonction *où que soit l'optimum* ($\Delta \approx 0$, non biaisé — la recherche aléatoire uniforme en est le contrôle canonique) ou s'il n'exploite que le placement central ($\Delta \gg 0$, biaisé vers le centre). Huit optimiseurs sont confrontés : **Random** (contrôle *seedé* `seed:7`, la référence non biaisée), **GA**, et les six composés géométriques **WOA, EO, FBI, Differential Evolution, Bare-Bones PSO, Recuit simulé** (Metropolis, 1953 ; Kirkpatrick, Gelatt & Vecchi, 1983). **Reproductibilité.** Le banc est **seedé** : `FastRandomRandomization.ResetSeed(masterSeed)` ancre le RNG global du framework une fois avant la suite, de sorte que les chiffres committés sont **reproduisibles** d'une exécution à l'autre — un étudiant qui ré-exécute le notebook retrouve exactement la table ci-dessous (le contrôle `Random` reste seedé séparément, `seed: 7`). + +Lecture honnête (G.9), fonction par fonction. **Sphere** (unimodale lisse) : tous les optimiseurs résolvent les deux cas (~0) → $\Delta \approx 0$ partout ; fonction trop facile pour révéler un biais. **Rastrigin** (fortement multimodale) : les $\Delta$ sont **bruités** — le contrôle Random lui-même y affiche le $\Delta$ le plus élevé (+7,9) ; à NFE = 5000 l'optimiseur tombe dans un optimum local différent selon le tirage, donc le $\Delta$ y mesure de la variance d'échantillonnage, pas un biais directionnel (la colonne *moyenne* qui agrège les trois fonctions est dominée par ce bruit et n'est pas un signal fiable). **Ackley** (puits central entouré de rides — la fonction *conçue* pour exposer le biais central) : **seul WOA** affiche $\Delta \gg 0$ (+4,36) — il résout Ackley centrée (~0) mais **rate** Ackley déplacée (4,36), signant un biais central net ; tous les autres (GA, EO, FBI, DE, BBPSO, Recuit simulé) résolvent les deux cas (~0) et sont **robustes** au déplacement. Leçon affûtée de « composants > métaphores » : ce n'est pas l'étiquette métaphorique (baleine, équilibre, criminalistique) qui prédit le biais — EO, FBI et BBPSO sont eux aussi « métaphoriques » mais robustes — c'est la **structure de l'opérateur**. L'encerclement de la meilleure position (le *bubble-net* de WOA) ancre la recherche sur le meilleur courant, qui sur une fonction à optimum central démarre près du centre → biais. Les opérateurs d'exploration arithmétique (**DE**, $v = r_1 + F \cdot (r_2 - r_3)$, même couche géométrique `GeometricCrossover`/`MatchMetaHeuristic` que WOA) et la perturbation gaussienne isotrope du **Recuit simulé** (critère de Metropolis) n'ancrent pas → robustesse. Ce n'est donc pas l'étiquette « métaphore » qui biaise vers le centre, mais l'ancrage de l'opérateur à un attracteur géométrique fixe. Leçon de lecture (honnêteté, G.9) : un $\Delta$ élevé n'est un *biais* que si l'optimiseur résolvait effectivement le cas centré ; sinon il signe juste de la faiblesse — d'où trois exercices (stabilité multi-graine de la signature, balayage de l'amplitude du déplacement, extension de la suite à Rosenbrock et Griewank). + +### 11 — Synergie d'îles complémentaires + +La composition est-elle **magique** ? Combiner un bon explorateur et un bon exploiteur dans un archipel hétérogène produit-il mécaniquement une synergie ? Ce notebook pose la question de façon **falsifiable** et y répond chiffres à l'appui. On assemble trois archipels de **même structure** (4 îles, migration `SmallMigrationRate`) via `IslandCompoundMetaheuristic` — (a) îles DE homogènes, (b) îles BBPSO homogènes, (c) 2 îles DE + 2 îles BBPSO hétérogène — et on les lance, à budget d'évaluations égal, sur Rastrigin et Ackley **dé-biaisées** en dimension 5 (optimum relocalisé hors centre via `ShiftedFitness` + `ShiftVectors.Seeded`). La dimension 5 (et non 2) est choisie pour que les opérateurs *différencient* : en dim 2, tous résolvent Rastrigin (objectif 0), rendant une synergie indiscernable. Un **GIF multicolore** (overlay `individualColors` + `EncodeAnimatedGif`) colore chaque individu par son île (DE en orange, BBPSO en vert) : la répartition exploration / exploitation devient visible génération après génération. **Verdict honnête (résultat négatif)** : sur les deux fonctions, l'archipel hétérogène est **battu** par le meilleur de ses constituants (0/2 synergie) — la migration entre opérateurs dissemblables peut *propager les solutions piégées* et produire un compromis *inférieur* au meilleur constituant. La synergie d'îles n'est pas automatique : elle se démontre, ne se décrète pas — la même leçon « composants > métaphores » (Sorensen 2015) poussée jusqu'à la *mesure* de la composition. Caveats : graine unique (pas un banc multi-graines ; banc rigoureux rote = #3963), GIF 2D illustratif alors que le banc est en dim 5. + +### 12 — Alignement d'axes + +MGS-10 instrumentait le biais **central** (un optimum à l'origine flatte les optimiseurs qui démarrent au centre) ; ce notebook instrumente le biais **complémentaire** des bancs CEC : l'**alignement d'axes**. On introduit le décorateur compositionnel `RotatedFitness` du fork — l'analogue de `ShiftedFitness` pour la rotation — qui évalue la fonction interne sur des coordonnées rotationnées $f_{\text{rot}}(x) = f(M x)$, où $M$ est une matrice orthogonale ($M M^\top = I$) fabriquée par le factory `RotationMatrices.Seeded(n, seed)` comme **produit de rotations de Givens** (orthogonale par construction, reproductible par $(n, \text{seed})$). Comme `ShiftedFitness`, c'est un décorateur fin : les mathématiques des fonctions canoniques sont réutilisées telles quelles (jamais réimplémentées), seules les coordonnées sont linéairement transformées. + +La **partie A** valide le décorateur contre la géométrie : sur Sphere (purement radiale, invariante par construction) la rotation est un no-op ; sur Rastrigin (terme $\sum \cos(2\pi x_i)$ séparable, un cosinus par axe) la rotation brise la séparabilité — la rotation *mesure* donc la séparabilité d'une fonction, c'est exactement pourquoi les suites CEC les rotationnent. La **partie B** montre la discrimination géométrique : sur Rosenbrock (asymétrique, vallée banane), la rotation conserve la *valeur* de l'optimum ($\approx 0$) mais en **déplace la position** — l'optimiseur aligné sur les axes ne peut plus descendre coordonnée par coordonnée. + +La **partie C** confronte les optimiseurs au banc : signature $\Delta = f^\star_{\text{roté}} - f^\star_{\text{non roté}}$ (le RNG est reseedé avant chaque paire pour isoler l'effet du paysage, pas du hasard). **Lecture honnête (G.9)** : en dimension 2 et à ce budget, $\Delta \approx 0$ pour **tous** — Rosenbrock 2D est assez facile pour que GA, WOA, DE, BBPSO la résolvent à zéro, rotationnée ou non ; il n'y a alors **pas de marge** pour qu'un alignement sur les axes pénalise. Un banc honnête ne « prouve » un biais opérateur que si le problème est assez dur pour que le biais ait de la place pour se manifester : ici le signal net est dans la **géométrie du paysage** (parties A/B), et complexifier le problème (dimension plus élevée, budget plus serré) pour révéler l'effet *opérateur* — un $\Delta$ qui sépare les déplacements composante par composant (crossover uniforme, WOA) des déplacements vectoriels (DE) — est précisément l'objet de l'exercice 2. On retrouve l'esprit de MGS-10 : on juge un optimiseur sur la **structure de ses opérateurs** (vectoriels vs composante par composant, centrés vs non), pas sur le nom de sa métaphore — et un banc honnête doit tester les **deux** biais CEC (`ShiftedFitness` + `RotatedFitness`, composables en la variante CEC complète `new RotatedFitness(new ShiftedFitness(inner, o), M)`). + +### 13 — Paysages dé-biaisés (visualisation) + +Là où MGS-12 *mesure* numériquement la signature d'alignement d'axes ($\Delta \approx +2847$ pour le GA sur Rastrigin rotatée contre $\approx +2$ pour le DE), ce notebook la **montre** géométriquement. On consomme le décorateur `RotatedFitness` ($f_{\text{rot}}(x)=f(M x)$, $M$ orthogonale) et l'on rend, en vraies heatmaps PNG via `SkiaLandscapeRenderer`, le paysage de fitness avant/après rotation. **Partie B — témoin de contrôle** : Sphere est invariante par rotation (une matrice orthogonale préserve la norme), les deux paysages sont donc identiques pixel pour pixel (écart numérique $\sim 10^{-15}$) — la validation que le décorateur est correct, toute différence observée plus loin provient bien de la géométrie. **Partie C** : la « vallée banane » de Rosenbrock pivote à 45°, l'optimum déménage de $(1,1)$ à $(\sqrt 2, 0)$, un terme croisé apparaît — la séparabilité est visiblement détruite. **Partie D** : les crêtes cosinus de Rastrigin basculent hors de la grille d'échantillonnage axe-par-axe — c'est le mécanisme géométrique exact derrière le $\Delta$ du GA mesuré en MGS-12. **Partie E** : la composition CEC `new RotatedFitness(new ShiftedFitness(inner, o), M)` combine déplacement et rotation ; l'optimum atterrit en $M^\top o$ et le paysage est doublement dé-biaisé. Les mathématiques canoniques ne sont jamais réimplémentées : seules les coordonnées sont transformées par les décorateurs compositionnels. Trois exercices prolongent (Ackley rotatée, recherche sur grille de l'optimum relocalisé, composition shift+rotate sur Schwefel). + +[![Rastrigin après rotation : les crêtes cosinus, alignées sur les axes à l'origine, basculent hors de la grille — la séparabilité est visiblement détruite](assets/readme/mgs13-rotation.png)](MGS-13-LandscapeDebias.ipynb) + +### 14 — Une synergie trouvée (et un cas négatif) + +MGS-11 avait **cherché** une synergie island-mix et l'avait honnêtement déclarée **absente** (0/2). Ce notebook revient sur ce verdict négatif avec une question de méthode : *était-ce l'absence de synergie, ou une migration mal calibrée qui diluait le meilleur îlot ?* Le modèle insulaire expose trois boutons (`GlobalMigrationRate`, `MigrationsGenerationPeriod`, ratio des îlots via les `shares`) ; MGS-11 les laissait par défaut (`SmallMigrationRate`, période 10) — un brassage qui noie le petit îlot exploitateur dans la population exploratrice avant qu'il n'ait fini de raffiner. Hypothèse : en réduisant le brassage (période 20) **et** en déséquilibrant le ratio (3 îlots DE explorateurs + 1 îlot BBPSO raffineur), l'îlot exploitateur survit assez pour exploiter ce que les explorateurs découvrent. + +Le banc est **multi-seed** (5 graines), à budget d'évaluations égal (1600 evals/archipel), sur Ackley et Rastrigin **dé-biaisées** en dimension 5, avec un **contrôle propre** : constituants (`DE-hom`, `BB-hom`) et combo candidate (`DE+BB-3:1`) partagent tous la même migration (`RandomRing`, taux 0.05, période 20) — seul le **ratio** varie, ce qui isole l'effet du ratio de l'effet de la migration. **Verdict mesuré** : sur Ackley, `DE+BB-3:1` bat **simultanément** ses deux constituants **5 graines sur 5** (fitness -0.309 vs DE-hom -2.302 et BB-hom -6.994) — la synergie est réelle et reproductible. Sur Rastrigin, `DE-hom` reste le meilleur et la même manipulation de ratio *dégrade* la fitness (-4.017 → -6.429) : **pas de synergie**. Leçon : la synergie island-mix existe mais est **conditionnelle** au paysage — Ackley (large cratère à puits profond) récompense l'exploration massive de DE *plus* le raffinement focalisé de BBPSO ; Rastrigin (forêt de minima réguliers) est mieux servi par l'exploration pure. Un **GIF multicolore** colore chaque individu par son îlot (DE orange, BBPSO vert) sur la convergence Ackley 2-D : on voit l'exploration orange se disperser puis converger, l'îlot vert raffiner sans être absorbé trop tôt. Un verdict négatif (MGS-11) n'est donc pas absolu — la bonne question n'est pas *« y a-t-il synergie ? »* mais *« à quelles conditions ? »*. Trois exercices prolongent (autre mode de migration, dimension 10, second cas de synergie sur Rosenbrock). + +### 15 — Le nombre derrière la heatmap : FDC globale + rugosité locale + +MGS-8 à MGS-13 nous ont donné l'**œil** : on *voit* la surface de fitness en couleur. Mais la visualisation est trompée par l'échelle, la rotation, le nombre de dimensions — deux paysages semblables peuvent être radicalement inégaux pour un algorithme. Ce notebook passe de l'**image au nombre** en introduisant la **Fitness Distance Correlation (FDC)** — Jones & Forrest (1995) — la métrique la plus utilisée pour prédire la difficulté d'un paysage. L'idée : un paysage est *facile* si la valeur de fitness est un bon indicateur de la distance au but ; tant que « mieux en fitness » rime avec « plus proche de l'optimum », un algorithme glouton ou génétique suit le gradient et converge. + +On calcule $\mathrm{FDC} = \rho(f(x), d(x, x^\star))$ (Pearson entre fitness brute et distance à l'optimum global) en **échantillonnant N points** uniformément dans la boîte de recherche, en **réutilisant la vraie infrastructure** de MGS-8 : le `DoubleArrayChromosome`, les bornes `KnownFunctionsBounds.For(...)`, et les **vraies** `IFitness.Evaluate` du fork (composition, jamais de réimplémentation — la fitness est celle du moteur, pas une recopie). Trois benchmarks contrastés où l'œil hésite : Sphere (unimodal), Rastrigin (multimodal), Ackley (structure fine). **Verdict FDC** : Sphere obtient FDC ≈ 0,976 (la fitness guide presque parfaitement, paysage facile), Rastrigin chute à 0,713 (les pièges locaux dispersent la relation fitness–distance), Ackley à 0,766 (intermédiaire). Le **nuage fitness–distance** rendu en SVG inline montre *pourquoi* : Sphere dessine un croissant propre (fitness ≈ distance²), Rastrigin disperse verticalement (à distance égale, plusieurs bassins). + +Mais la FDC ne mesure qu'une corrélation *globale* — elle ne dit rien de la **rugosité locale**. Le notebook introduit donc une **deuxième famille de métriques**, elle aussi réutilisant la vraie fitness du fork mais via une **marche aléatoire** (et non un tirage uniforme) : l'**autocorrélation de lag 1** $\rho_1$ (Weinberger 1990) et la **longueur de corrélation** $L = -1/\ln\rho_1$ — à quelle distance la fitness se décorréle-t-elle ? — ainsi que la **neutralité** (proportion de pas neutres, révélatrice des plateaux). **Verdict rugosité** : Sphere reste très lisse ($\rho_1 \approx 0{,}97$, $L \approx 30$ pas), Rastrigin s'effondre ($\rho_1 \approx 0{,}37$, $L \approx 1$ pas — le gradient local est du pur bruit, chaque pas décorréle), Ackley intermédiaire ($L \approx 10$). C'est l'explication **mécaniste** du verdict FDC : Rastrigin a une FDC basse non pas parce que sa fitness « ne guide pas » en moyenne, mais parce qu'à l'échelle locale elle **oscille** si vite qu'un glouton s'y empêtre. La **neutralité** rend un verdict honnête : quasi-nulle partout (~0–2 %) — ces benchmarks *continus* n'ont pas de plateaux, la métrique discrimine les paysages *discrets* (NK, SAT), pas ceux-ci. **Chaque métrique a son terrain** : les deux ensemble diagnostiquent ce que chacune, seule, masque — et justififie rétrospectivement pourquoi MGS-10 trouvait WOA biaisé sur Ackley (FDC intermédiaire *et* rugosité élevée : la fitness guide mal *et* oscille vite). Quatre exercices prolongent (FDC de Griewank, effet de la dimension, déception via Schwefel, rugosité de la vallée courbe de Rosenbrock). + +### 16 — Capstone : sélectionner le bon optimiseur (cadre de Rice, No-Free-Lunch) + +MGS-15 avait donné les **métriques** du paysage ; MGS-10 le **portfolio** mesuré de 8 optimiseurs. Ce notebook capstone referme la boucle : si aucun optimiseur ne gagne partout (théorème No-Free-Lunch, Wolpert & Macready 1997), alors le choix doit être *informé par le problème*. On applique le **cadre de sélection d'algorithme de Rice (1976)** — *features → algorithme du portfolio → performance* — en **réutilisant verbatim** l'infrastructure des deux notebooks précédents : le portfolio de 8 optimiseurs (Random, GA, WOA, EO, FBI, DE, BBPSO, SA via `MakeOptimizer` + `MetaHeuristicsService.CreateMetaHeuristicByName`) et les features de paysage (`Fdc`, `AutocorrLag1` via `RandomWalk`, `NeutralRatio`, `record LandscapeReport`). + +L'arc est celui d'une expérience complète : (1) **oracle** — le banc `CenterBiasBenchmark` (Kudela 2022) mesure le regret $\Delta$ des 8 optimiseurs sur Sphere/Rastrigin/Ackley (vérité terrain) ; on agrège en **pire-cas** (et non moyenne, bruitée par Rastrigin) : DE, BBPSO, EO sont robustes (aucune fonction où ils s'effondrent), WOA s'effondre sur Ackley ($\Delta = +4{,}19$ — exactement le biais central de MGS-10). (2) **Features** — on décrit les trois paysages *sans les optimiser* (FDC Sphere 0,99 / Rastrigin 0,74 ; $\rho_1$ Sphere 0,98 / Rastrigin 0,62). (3) **Sélecteur heuristique** — une règle lisible (Rice) qui, des features, recommande l'optimiseur adapté et signale ceux à éviter ; recoupée contre l'oracle, elle est **ALIGNÉE** sur les trois paysages et évite correctement WOA sur Ackley. (4) **Généralisation** — un quatrième paysage jamais vu, Rosenbrock (vallée banane) : le sélecteur recommande DE/BBPSO qui atterrissent dans le top-3 réel — mais la feature FDC s'y révèle **trompeuse** (Rosenbrock est unimodale et lisse, pourtant FDC ≈ 0,71 : la métrique radiale ne capte pas la *vallée courbe*). **Leçon honnête** : les features de paysage orientent vers les bons optimiseurs et écartent les catastrophes évidentes, mais elles manquent la géométrie directionnelle — un FDC bas signifie tantôt « multimodal » (Rastrigin) tantôt « courbé » (Rosenbrock), et la feature seule ne distingue pas les deux. C'est le **capstone** de la Partie 4 : on est parti de métaheuristiques isolées, on les a mesurées (portfolio), on a appris à décrire les problèmes (paysage), et l'on sait désormais faire correspondre les deux — le No-Free-Lunch n'est pas une condamnation mais l'invitation à *raisonner sur le problème avant de lancer l'algorithme*. Quatre exercices prolongent (paysage neutre quantifié, sélecteur fondé sur le coût d'évaluation, limite du FDC sur Schwefel, vers un sélecteur appris par k-NN). + +### 17 — Deuxième réponse au No-Free-Lunch : contrôler les paramètres pendant la course (Eiben 1999) + +MGS-16 répondait au No-Free-Lunch en **sélectionnant** le bon algorithme pour le paysage. MGS-17 donne la **seconde réponse classique** : un *même* algorithme, mais dont on **adapte les paramètres pendant la course**. C'est la distinction de Karafotias et al. (2015) — reprise d'Eiben et al. (1999) — entre le **tuning** (réglage *offline*, fixe, le pari « un taux pour toute la course ») et le **control** (adaptation *online*, dynamique). Trois types de control sont distingués par la taxonomie d'Eiben : **déterministe** (un schedule $p(g)$ fonction de la génération), **adaptatif** (un feedback de l'état de la population), **self-adaptatif** (le taux encodé *par individu*). + +Le notebook exploite le **vrai moteur du fork** — pas une réimplémentation. Le hook est `ProbabilityConfig.DynamicProbability : Func` combiné à `ProbabilityStrategy.OverwriteProbability` : à chaque évaluation, le solveur appelle `DynamicProbability(ctx, initial)` et **écrase** la probabilité de mutation du GA. Le `ctx` expose `Population.GenerationsNumber` (déterministe), les statistiques de population (adaptatif) et l'`OriginalIndex` de l'individu (self-adaptatif). C'est exactement la granularité que la taxonomie d'Eiben décrit — et le fork la fournit nativement. L'infrastructure est réutilisée verbatim depuis MGS-10/15/16 (`DoubleArrayChromosome`, `MakeOptimizer`, `RunAvg` sur 5 graines, `KnownFunctionsBounds`, `RastriginFitness`/`SphereFitness`). + +L'arc est une démonstration à quatre bras, **budgétée à parts égales** (mêmes NFE = 5000, mêmes 5 graines {7,42,99,123,777}, pour ne pas tricher par le budget) : (1) **tuning fixe** — un sweep $p \in \{0{,}01, 0{,}05, 0{,}20, 0{,}50\}$ sur Rastrigin, le meilleur est $p=0{,}05$ (objectif 11,885) ; leçon : aucun taux fixe n'est robuste. (2) **control déterministe** — un schedule de décroissance exponentielle $p(g) = 0{,}5 \cdot e^{-3g/G}$ (explore tôt, exploite tard), dont la trace imprimée montre la probabilité chuter de 0,500 à 0,025. (3) **control adaptatif** — la probabilité suit un signal de diversité (écart-type du 1er gène de la génération courante). (4) **control self-adaptatif** — chaque individu porte son propre taux (grille par index), la population est **hétérogène**. **La leçon centrale (No-Free-Lunch du paramètre)** : sur Rastrigin, le self-adaptatif gagne nettement (9,944 — il *hedging* : à chaque instant, une sous-population a le bon taux pour la phase courante, l'`EliteSelection` préserve le meilleur des deux mondes) ; mais sur Sphere, **l'ordre s'inverse** — le réglage fixe timide ($p=0{,}05$) et le decay mènent (0,750 / 0,711), le self-adaptatif est dernier (1,066) : la mutation qui aidait à *échapper* aux minima locaux de Rastrigin ne fait que *bruiter* la convergence facile de Sphere. Aucune stratégie ne domine sur les deux paysages. C'est le miroir exact de MGS-16 : là où l'algorithme était paysage-dépendant, ici c'est le **paramètre** — et l'honnêteté du banc (succès Rastrigin **et** échec Sphere) évite de réciter « le contrôle c'est toujours mieux » que les données démentent. Quatre exercices prolongent (schedule linéaire, règle 1/5 de Rechenberg par taux de succès, vrai chromosome self-adaptatif d'Évolution Strategies, contrôle du crossover). + +### 18 — Banc CEC consolidé : shift+rotate combinés, le protocole standard de dé-biais + +MGS-10 isolait le **décalage** de l'optimum, MGS-12 la **rotation** des axes. Les benchmarks *réels* du Congress on Evolutionary Computation (CEC) font les deux à la fois : une fonction est *à la fois* translatée et rotatée, et c'est cette composition qui définit le standard de test des métaheuristiques depuis CEC 2005/2017. MGS-18 **consolide** ce protocole : il confronte les 8 optimiseurs du portfolio (verbatim MGS-16) à **quatre variantes** — plain, shifted, rotated, **combined** — en étendant `CenterBiasBenchmark` (qui n'en proposait que deux). + +L'infrastructure est réutilisée verbatim : les décorateurs composes du fork `ShiftedFitness(inner, offset)` et `RotatedFitness(inner, M)` sont **composables** par construction — `RotatedFitness(ShiftedFitness(inner, Off), M)` applique la translation *puis* la rotation. `ShiftVectors.Seeded(n, magnitude, seed)` et `RotationMatrices.Seeded(n, seed)` (orthogonale via produit de rotations de Givens) garantissent la reproductibilité. La sanity check est **non dégénérée** (point test $x=(1,2,3,4,5)$ : les 4 variantes donnent 4 valeurs distinctes 9,70 / 12,20 / 10,72 / 13,05 — les décorateurs transforment bien la fonction). + +La thèse est **structurelle** : les biais isolés de MGS-10 et MGS-12 **se composent** sous shift+rotate combiné. Mais l'effet du combined est **paysage-dépendant**, pas universellement pire. Sur **Ackley** : EO, FBI et DE résolvent les 4 variantes (~0) ; WOA s'effondre sur le cas *shifted* seul (2,97 — son biais central MGS-10) et GA sur le *rotated* seul (3,24 — son biais d'axe MGS-12) ; le combined de WOA est **sub-additif** (2,73 < shifted 2,97 — la rotation masque le décalage). Sur **Rosenbrock**, l'histoire s'inverse : le combined de WOA (6,91) **dépasse** à la fois le shifted (5,19) et le rotated (3,13) — **super-additif** (+1,41 : les deux biais se renforcent). Aucun optimiseur ne domine les 4 variantes sur les 2 paysages : DE est le plus robuste (pire-cas 1,71), WOA et Random « à éviter ». L'honnêteté du banc (sub-additif sur Ackley **et** super-additif sur Rosenbrock) évite le faux cadrage « le combined aggrave toujours » — un récit plus riche, fidèle aux données. Quatre exercices prolongent (nouvelle rotation seedée, rotation non-orthogonale, grand-angle, banc CEC complet 10 fonctions). + +### 19 — Recuit simulé décomposé : l'opérateur de Metropolis isolé + +MGS-10 confrontait le **recuit simulé** comme une boîte noire. Mais dans le fork, `SimulatedAnnealing` n'est pas un monolithe : c'est un **composé** assemblant une **perturbation gaussienne** (le croisement qui produit un voisin de l'individu courant) et une **réinsertion de Metropolis** (`MetropolisReinsertion`) qui accepte ou rejette ce voisin selon le critère $P = \exp(\Delta / T_k)$. MGS-19 **débranche** ce deuxième ingrédient et le rebranche **seul** sur un GA standard (croisement de recombinaison `UniformCrossover`, pas perturbation), via l'injection `ga.Reinsertion = reins`. C'est la thèse « composants > métaphores » poussée jusqu'au **démontage du recuit lui-même** : la métaphore thermodynamique est-elle indivisible, ou l'opérateur de survie est-il réutilisable ailleurs ? + +Le banc isole l'effet de la **règle d'acceptation** à appariement constant : cinq configurations (`FitnessBasedPairwiseReinsertion` contrôle greedy, trois `MetropolisReinsertion` à températures froide/moyenne/chaude, `FitnessBasedElitistReinsertion` référence μ+λ) partagent le même croisement, la même mutation, la même sélection — seul le critère de survie varie. Budget commun (NFE = 5000, dim 5, 3 graines seedées → chiffres reproduisibles) sur Sphere (témoin neutre unimodal), Rastrigin et Ackley (multimodales). **Verdict honnête (résultat négatif, G.9)** : sur Sphere, l'annealing ne sert à rien (témoin neutre attendu) et le réglage chaud dégrade (≈ 0,10 contre ≈ 0,01) ; sur Rastrigin et Ackley, **aucun** réglage Metropolis n'améliore le contrôle greedy pairwise — le plus chaud est le **pire**. L'hypothèse naturelle (accepter des enfants moins bons aide à franchir les cols) est **réfutée**. L'explication la plus plausible est sémantique : dans SA l'enfant est un **voisin** du parent, donc accepter un moins bon voisin = explorer le voisinage ; ici l'enfant est un **recombinant** de deux parents (mosaïque par gène), donc accepter un recombinant moins bon n'est pas une exploration — c'est du bruit. **Le bénéfice du recuit réside dans le couplage** perturbation+acceptation, pas dans l'acceptation seule. C'est la leçon « composants > métaphores » dans sa forme la plus exigeante : on PEUT démonter SA, l'opérateur isolé FONCTIONNE sur le vrai moteur — mais il ne porte pas, à lui seul, le bénéfice du tout (écho de la synergie conditionnelle de MGS-11/14 : la composition n'est magique ni assemblée ni désassemblée). Une **limite frozen** (T→0 ⇒ règle greedy), vérifiée sur le témoin lisse Sphere (résidu = divergence de trajectoire RNG, non un effet d'acceptation), referme la cohérence. Trois exercices prolongent (schedule lent vs rapide, recombiner la perturbation pour restaurer le couplage, composition insulaire de l'opérateur). + +### 21 — Représentation vs algorithme : le plan croisé Sudoku + +MGS-16/17 répondaient au No-Free-Lunch en changeant *d'algorithme* ou *de paramètres*. Ce notebook pose la question en amont d'eux : **et si le facteur dominant n'était ni l'algorithme ni ses paramètres, mais la représentation ?** Sudoku-05 (Tranches 3 et 4) avait comparé des moteurs sur des représentations différentes *par morceaux*, sans pouvoir attribuer l'effet à l'un ou l'autre facteur ; MGS-21 mène l'expérience **croisée** propre : deux représentations — **R1**, le vecteur continu $[1,10)^{36}$ décodé par arrondi+clamp (chromosome `double` sur le vrai moteur MGS), **R2**, la grille où chaque ligne est une permutation des chiffres manquants (algèbre de swaps Move/Minus/Times de Hernandez & Gonzalez, *Metaheuristics in C#*, MIT 2012 — la vitesse est une liste de swaps sur cellules vides, chaque ligne reste une permutation par construction) — croisées avec deux moteurs, le **PSO** composé (`MetaHeuristicsService.CreateMetaHeuristicByName("ParticleSwarmOptimization")`) et un **GA** à permutations (croisement par lignes, mutation swap). Même grille (Easy[0] de Sudoku_Easy51, 36 vides), même fonction de coût (conflits lignes+colonnes+blocs), même budget (~8 000 évaluations), 4 graines {0,1,7,42} par cellule — et un **critère de verdict pré-enregistré** : « la représentation domine » exige que l'écart R1→R2 dépasse, dans chaque colonne, les écarts entre algorithmes. + +**Verdict honnête en deux temps (G.9)** : sur la colonne PSO, la représentation domine — la médiane passe de 45,0 à 6,0 conflits (−39), davantage que le meilleur effet algorithme ne le rapproche (−34,5) ; sur la colonne GA, les deux facteurs pèsent du même ordre (10,5 → 0,0 côté représentation, ×4,3 côté algorithme) — et seule leur **combinaison** R2×GA résout : **4/4 graines à 0 conflit**, aucune cellule R1 ne s'approchant de la solution (minimum 4). La cellule de **cause** explique pourquoi l'écart est structurel et non dynamique : 200 candidats R1 sur 200 (100 %) tombent hors de l'espace admissible après décodage (l'arrondi est une projection discontinue qui détruit l'information de proximité), contre 0/200 pour R2 par construction ; un candidat R1 aléatoire part à 67,9 conflits en moyenne contre 37,4 en R2 — les conflits de lignes que R2 rend *impossibles*, R1 les porte presque tous dès le tirage. C'est la version mesurée du geste « changer de représentation plutôt qu'insister » : avant de régler `w`, `c1` ou `c2`, demander ce que le décodage détruit. Trois exercices prolongent (rejouer le croisement sur une seconde grille, recuit simulé sur les deux représentations, diversité effective par grille décodée distincte). + +> Numérotation : MGS-20 (langage de composition, [#12224](https://github.com/jsboige/CoursIA/issues/12224)) est en préparation — MGS-21 a été livré indépendamment car le plan croisé ne dépend pas du langage de composition. + +## Conventions + +- **Représentation agnostique.** Les composés géométriques (WOA, EO) requièrent un chromosome qui stocke les gènes en `double` de façon transparente. Les notebooks définissent un `DoubleArrayChromosome` (assistant de test, non livré dans la lib) avec `CreateNew()` randomisant dans les bornes — indispensable pour la diversité initiale d'un benchmark. +- **Fitness = négation.** GeneticSharp *maximise* le fitness ; chaque `Evaluate()` des fonctions benchmark renvoie donc l'objectif nié. La lib pinne cette convention par [tests unitaires](https://github.com/jsboige/MetaGeneticSharp/blob/main/tests/MetaGeneticSharp.Extensions.Tests/KnownFunctionsTests.cs) (optimum à x* + négation). + +## Boucle CoursIA ↔ fork + +Le code de la bibliothèque vit dans le **fork** [jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp), monté ici comme sous-module (`MyIA.AI.Notebooks/Search/MetaGeneticSharp/`). Les notebooks pédagogiques (ce répertoire) sont propriété du dépôt CoursIA et consomment la bibliothèque via ses DLLs buildées. Ce point d'entrée ferme la boucle : depuis la série Search Python (Parties 1-2), on bascule vers le side track C#, qui redirige à son tour vers le fork pour le code source complet, les tests et la feuille de route. + +## Références + +Les métaheuristiques reconstruites dans cette partie suivent les articles fondateurs. Les liens bibliothèque (GeneticSharp, fork MGS) sont regroupés dans la section « Liens » ci-dessous. + +| Notebook(s) | Métaheuristique | Référence | +|-------------|-----------------|-----------| +| MGS-1 (Introduction) | Algorithme génétique | Holland, J. H. (1975) — *Adaptation in Natural and Artificial Systems*. University of Michigan Press. | +| MGS-5 (Compound), MGS-6 (Benchmarks) | Whale Optimization Algorithm | Mirjalili, S., & Lewis, A. (2016) — « The Whale Optimization Algorithm », *Advances in Engineering Software* 95. | +| MGS-5 (Compound), MGS-9 (EverestRelief) | Equilibrium Optimizer | Faramarzi, A., Heidarinejad, M., Stephens, B., & Mirjalili, S. (2020) — « Equilibrium optimizer: A novel optimization algorithm », *Knowledge-Based Systems* 197. | +| MGS-10 (CenterBias) | Differential Evolution | Storn, R., & Price, K. (1997) — « Differential Evolution – A Simple and Efficient Heuristic for Global Optimization over Continuous Spaces », *Journal of Global Optimization* 11. | +| MGS-10 (CenterBias), MGS-28 ([BareBonesPSO-vs-Mealpy](MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb)) | Bare-Bones Particle Swarm | Kennedy, J. (2003) — « Bare Bones Particle Swarms », *Proc. IEEE Swarm Intelligence Symposium*. | +| MGS-10 (CenterBias), MGS-19 (MetropolisReinsertion) | Recuit simulé (Simulated Annealing) | Metropolis, N., Rosenbluth, A. W., Rosenbluth, M. N., Teller, A. H., & Teller, E. (1953) — « Equation of State Calculations by Fast Computing Machines », *Journal of Chemical Physics* 21(6) ; Kirkpatrick, S., Gelatt, C. D., & Vecchi, M. P. (1983) — « Optimization by Simulated Annealing », *Science* 220(4598). | +| MGS-10 (CenterBias) | Test du biais central (centré-vs-déplacé) | Kudela, H. (2022) — protocole centré-vs-déplacé (centered-vs-shifted). | +| MGS-11 (IslandSynergy), MGS-19 (MetropolisReinsertion) | Modèle insulaire, synergie d'îles hétérogènes ; démontage d'un composé (composants > métaphores) | Sørensen, K. (2015) — « Metaheuristics—the metaphor exposed », *Intl. Trans. in Operational Research* 22(1). doi:10.1111/itor.12001 | +| MGS-9 (EverestRelief) | Particle Swarm Optimization (baseline) | Kennedy, J., & Eberhart, R. (1995) — « Particle Swarm Optimization », *Proc. IEEE Int. Conf. on Neural Networks*. | +| MGS-6, MGS-7, MGS-16 | No-Free-Lunch | Wolpert, D. H., & Macready, W. G. (1997) — « No free lunch theorems for optimization », *IEEE Trans. on Evolutionary Computation* 1(1). | +| MGS-16 (AlgorithmSelection) | Cadre de sélection d'algorithme | Rice, J. R. (1976) — « The Algorithm Selection Problem », *Advances in Computers* 15. doi:10.1016/S0065-2458(08)60520-3 | +| MGS-17 (ParameterControl) | Taxonomie tuning vs parameter control | Eiben, A. E., Hinterding, R., & Michalewicz, Z. (1999) — « Parameter Control in Evolutionary Algorithms », *IEEE Trans. on Evolutionary Computation* 3(2). doi:10.1109/4235.771166 | +| MGS-17 (ParameterControl) | État de l'art du parameter control | Karafotias, G., Hoogendoorn, M., & Eiben, A. E. (2015) — « Parameter Control in Evolutionary Algorithms: A Tutorial », *Evolutionary Computation* 23(2). doi:10.1162/EVCO_r_00136 | +| MGS-17 (Exercice 2) | Règle 1/5 (control adaptatif par succès) | Rechenberg, I. (1973) — *Evolutionsstrategie: Optimierung technischer Systeme nach Prinzipien der biologischen Evolution*. Frommann-Holzboog. (cf. Schwefel, H.-P. (1995), *Evolution and Optimum Seeking*, Wiley.) | +| MGS-18 (CecBanc) | Protocole CEC (shift+rotate composés) | Awad, N. H., Ali, M. Z., Suganthan, P. N., & Reynolds, R. G. (2016) — « Problem Definitions and Evaluation Criteria for the CEC2017 Special Session and Competition on Single Objective Real-Parameter Optimization », *Technical Report*, Royal Melbourne Institute of Technology. (suite de CEC2005 : Suganthan, P. N. et al. (2005).) | +| MGS-7 (Configs 3-4) | Croisement géométrique (Moraglio) | Moraglio, A. (2007) — *Towards a Geometric Unification of Evolutionary Algorithms*, PhD thesis, University of Essex. | +| MGS-21 (Representation) | Algèbre de swaps pour PSO discret (vitesse = liste de swaps) | Hernandez, A., & Gonzalez, Y. (2012) — *Metaheuristics in C#*. MIT, Universidad de La Habana (Common/DiscretePSO.cs). | + +--- + +## Conclusion / Prochaines étapes + +### Ce que vous avez appris + +Cette quatrième partie a changé la question : non plus *« quelle métaheuristique choisir »* (Parties 1-2), mais *« comment construire et combiner des métaheuristiques à partir de primitives »*. L'arc pédagogique, porté par trente-cinq notebooks C# .NET 9 au-dessus de [MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp), démontre la thèse **composants > métaphores** : + +- **Le moteur autonome** (MGS-1, MGS-2) — un `MetaGeneticAlgorithm` qui pilote l'évolution sans dépendre de la classe `GeneticAlgorithm` amont, et la grammaire fluente (`Match`, `Container`, `Scoped`) qui permet d'assembler une métaheuristique en quelques lignes déclaratives lisibles. C'est le socle : tout le reste compose au-dessus. +- **La structuration de population** (MGS-3, MGS-4) — le modèle eucaryote (sous-populations spécialisées portées par des chromosomes composites) et le modèle insulaire (îles migratoires) : deux configurations qu'aucune bibliothèque monolithique grand public n'offre directement, et qui deviennent naturelles une fois la composition maîtrisée. +- **La reconstruction des composés publiés** (MGS-5) — WOA, EO, FBI : pour chaque algorithme du catalogue, le parcours en trois temps (description → reconstruction depuis les primitives `BuildMainHeuristic()` → raccourci factory prouvant l'équivalence). C'est l'argument poussé jusqu'à la **preuve** : reconstruire un algorithme bio-inspiré *démontre* son mécanisme au lieu de le cacher derrière une métaphore animale (critique de Sørensen, 2015). +- **La confrontation honnête** (MGS-6) — dix fonctions benchmark standard, comparaison Uniform / WOA / Islands sans trier les victoires : WOA gagne ou égalise sur 7/10 mais **diverge sur Schwefel**, démonstration de No-Free-Lunch là où `mealpy` masquerait le mécanisme. +- **L'agnosticisme à la représentation** (MGS-7) — la même `IslandMetaHeuristic` appliquée à un TSP-20 (permutation) sans aucune adaptation : la grammaire vit *sous* la couche géométrique et ne lit jamais `Gene.Value`. Le transfert continu → combinatoire sans réécriture. Le notebook pousse plus loin la **théorie géométrique de Moraglio** (Configs 3 et 4) : deux métriques de permutation distinctes (swap/Cayley via `OrderedEmbedding`, insertion/Ulam via `InsertionEmbedding`) définissent deux segments géodésiques distincts entre les mêmes parents — preuve que **c'est l'embedding (le choix de la métrique) qui porte la géométrie, pas le moteur** : c'est le point du *deep learning géométrique* appliqué aux opérateurs génétiques. +- **La visualisation des paysages** (MGS-8, MGS-9) — de vraies heatmaps PNG (fonction analytique, carte d'altitude, relief terrestre réel Everest) qui rendent le choix d'une métaheuristique *éclairé* plutôt que *doctrinal*, et un flipbook de convergence montrant la population se contracter vers le sommet. +- **La caractérisation du biais central** (MGS-10) — le protocole centré-vs-déplacé (Kudela 2022) confronte huit optimiseurs (Random, GA, WOA, EO, FBI, DE, BBPSO, Recuit simulé) sur un banc **seedé** (chiffres reproduisibles). Lecture fonction par fonction : sur Sphere (trop facile) et Rastrigin (trop bruitée à NFE = 5000) le signal n'est pas fiable, mais sur **Ackley** — la fonction conçue pour exposer le biais — **seul WOA** présente un biais central ($\Delta = +4,36$ : il résout le cas centré mais rate le cas déplacé) ; les sept autres, y compris les composés « métaphoriques » EO, FBI, BBPSO, sont **robustes**. Leçon affûtée de « composants > métaphores » : ce n'est pas l'étiquette métaphorique qui prédit le biais — EO, FBI, BBPSO sont eux aussi métaphoriques mais robustes — c'est la **structure de l'opérateur** : l'encerclement de la meilleure position (WOA) ancre vers le centre, là où l'arithmétique libre (DE, Recuit simulé) ou le pool d'équilibre (EO) n'y ancrent pas. Une **seconde preuve**, plus fine, au-delà de la performance brute (MGS-6). +- **La mesure d'une synergie** (MGS-11) — la composition est-elle magique ? Un archipel hétérogène (îles DE exploratrices + îles BBPSO exploitantes) est confronté, à budget égal sur fonctions dé-biaisées en dim 5, à ses constituants homogènes. Verdict **négatif** (0/2 synergie) : la migration entre opérateurs dissemblables peut *propager les solutions piégées* et produire un compromis *inférieur* au meilleur constituant. La synergie d'îles n'est pas automatique — elle se **démontre**, ne se décrète pas : « composants > métaphores » poussée jusqu'à la *mesure falsifiable* de la composition. +- **La synergie retrouvée, et conditionnelle** (MGS-14) — retour critique sur le verdict négatif de MGS-11. En calibrant la migration (période 20 au lieu de 10) **et** le ratio exploration/exploitation (3 îlots DE + 1 îlot BBPSO), la combo `DE+BB-3:1` bat **simultanément** ses deux constituants sur Ackley, **5 graines sur 5** (contrôle propre : constituants et combo partagent la même migration, seul le ratio varie). Mais la même manipulation de ratio *dégrade* la fitness sur Rastrigin — la synergie est **conditionnelle** au paysage. Leçon de méthode : un verdict négatif n'est pas absolu, la bonne question est *« à quelles conditions ? »*, et un banc honnête rapporte succès (Ackley) **et** échec (Rastrigin). +- **Le capstone : sélectionner plutôt qu'invoquer** (MGS-16) — le No-Free-Lunch (Wolpert & Macready 1997) dit qu'aucun optimiseur ne domine ; le **cadre de Rice (1976)** (*features → portfolio → performance*) répond pragmatiquement. Le notebook **réunit les deux fils** — le portfolio de 8 optimiseurs (MGS-10) et les features de paysage (MGS-15) — et construit un sélecteur heuristique qui, des seules features mesurées, oriente vers les optimiseurs robustes (DE/BBPSO/EO) et **évite les catastrophes** (WOA sur Ackley, $\\Delta=+4{,}19$) sans avoir à tout exécuter. Validé sur les trois paysages connus, il est **éprouvé sur un quatrième jamais vu** (Rosenbrock) où la recommandation atterrit dans le top-3 réel — mais où le FDC se révèle trompeur (la vallée courbe n'est pas captée par la métrique radiale). C'est la fermeture de l'arc : décrire le problème (paysage) pour **faire correspondre** l'algorithme (portfolio), transformer le No-Free-Lunch d'une condamnation en méthode. +- **La deuxième réponse au No-Free-Lunch : contrôler le paramètre** (MGS-17) — là où MGS-16 changeait *d'algorithme* selon le paysage, MGS-17 garde le *même* algorithme et adapte ses **paramètres pendant la course** (taxonomie d'Eiben 1999 : tuning *fixe* vs control *déterministe* / *adaptatif* / *self-adaptatif*). Le notebook se branche sur le vrai moteur du fork — `ProbabilityConfig.DynamicProbability`, qui écrase la probabilité de mutation à chaque évaluation — et montre les trois types de control en acte : un schedule de décroissance, un feedback de diversité, des taux *par individu* (self-adaptatif hétérogène). La leçon est honnête : le contrôle **n'est pas universellement meilleur** — sur Rastrigin le self-adaptatif gagne nettement (il *hedging*, une sous-population a toujours le bon taux), mais sur Sphere **l'ordre s'inverse** (la mutation qui échappe aux minima de Rastrigin ne fait que bruiter la convergence facile de Sphere). **No-Free-Lunch au niveau du paramètre**, miroir exact de celui de l'algorithme (MGS-16) : les deux réponses classiques, ici réunies, disent la même chose — aucune stratégie n'est universelle, seul le *raisonnement sur le problème* (quel paysage ? quelle phase de course ?) l'est. +- **La consolidation du banc CEC : shift+rotate combinés** (MGS-18) — les benchmarks *réels* du Congress on Evolutionary Computation translatent **et** rotatent simultanément. Le notebook réunit les deux dé-biais étudiés isolément (décalage MGS-10, rotation MGS-12) dans le protocole composé canonique (`RotatedFitness(ShiftedFitness(inner, offset), M)`), confronte les 8 optimiseurs aux 4 variantes (plain / shifted / rotated / combined), et montre la thèse structurelle : **les biais isolés se composent** — mais l'effet du combined est *paysage-dépendant* (sub-additif sur Ackley pour WOA : la rotation masque le décalage ; super-additif sur Rosenbrock : les deux biais se renforcent), pas universellement pire. L'arc se ferme sur la *méthode* : un banc honnête rapporte ce qui aggrave **et** ce qui compense, et aucun optimiseur ne survit aux 4 variantes des 2 paysages — DE le plus robuste, WOA et Random à éviter. +- **Le démontage du recuit simulé : l'opérateur de Metropolis isolé** (MGS-19) — la thèse « composants > métaphores » éprouvée dans son sens le plus exigeant : non seulement on **reconstruit** un composé (MGS-5), mais on peut en **débrancher** un ingrédient et le rebrancher ailleurs. Le notebook isole `MetropolisReinsertion` du compound `SimulatedAnnealing` et l'injecte seul sur un GA de recombinaison (`ga.Reinsertion = reins`), à appariement constant avec un contrôle greedy pairwise. Verdict honnête **négatif** (G.9) : l'acceptation `exp(Δ/T)` détachée de la perturbation **n'aide pas** un GA à franchir les cols (sur Rastrigin/Ackley, tous les réglages Metropolis sous-performent le greedy, le plus chaud est le pire) — car l'enfant recombinant n'est pas un « voisin » du parent, donc accepter un moins bon enfant n'est quasiment que du bruit. Le bénéfice du recuit est dans le **couplage** perturbation+acceptation, pas dans l'acceptation seule. Démonter révèle la leçon finale : on PEUT décomposer un algorithme, l'opérateur isolé FONCTIONNE — mais le tout est plus que la somme de ses pièces, et c'est précisément en démontant qu'on le prouve. +- **La représentation au-dessus de l'algorithme** (MGS-21) — la question du No-Free-Lunch posée un niveau *au-dessus* du choix d'algorithme : à budget d'évaluations et fonction de coût égaux, un plan croisé 2×2 (représentation continue+arrondi vs permutations de lignes ; PSO vs GA) sur le Sudoku montre que le changement d'espace rapporte au PSO davantage que tout changement de moteur (−39 conflits contre −34,5), que seule la combinaison R2×GA résout (4/4 graines à 0 conflit, aucune cellule continue n'approchant la solution), et pourquoi : l'arrondi est une projection discontinue dont **100 % des candidats décodés** tombent hors de l'espace admissible. Avant de régler les paramètres d'un moteur, demander ce que le décodage détruit — la bonne réponse à un problème d'optimisation commence par la représentation, avant l'algorithme (MGS-16) et avant le paramètre (MGS-17). + +Le véritable enseignement rejoint celui des Parties 1-2 : aucune métaheuristique ne domine partout, et la bonne réponse à un problème d'optimisation est rarement « l'algorithme X » mais plutôt « **la bonne composition de primitives pour ce paysage de fitness** ». + +### Prochaines étapes + +- **Le code source de la bibliothèque** : le [fork jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — code source, tests unitaires, et feuille de route ([ROADMAP.md](https://github.com/jsboige/MetaGeneticSharp/blob/main/ROADMAP.md)) — prolonge cette partie vers une vraie bibliothèque industrialisable. Les notebooks ne sont que la vitrine pédagogique des briques qui y vivent. +- **Retour aux fondamentaux Python** : après avoir reconstruit WOA et EO à la main, reprendre [Search-11-Metaheuristics](../Part1-Foundations/Search-11-Metaheuristics.ipynb) (PSO, ABC, SA, BRO via `mealpy`) — l'appel de fonction y apparaît alors comme un *raccourci* au-dessus des mécanismes qu'on vient de reconstruire, et l'on mesure ce que la composition déclarative apporte. +- **Le pont vers l'ingénierie** : les patterns de composition (sous-populations spécialisées, migration, hybrides assemblés par grammaire fluente) existent dans la littérature mais sont rares dans les libs grand public — cette partie est le socle pour les implémenter en production sur un runtime .NET typé. +- **La série dans son ensemble** : le [sommaire Search](../README.md) cartographie les quatre parties — celle-ci est le side track C# .NET qui démontre que les concepts Python (Search-5 génétique, Search-11 métaheuristiques) se retrouvent, solidement typés et composables, dans un vrai moteur. + +### Le fil rouge + +Les métaheuristiques composables proposent un changement de regard sur l'optimisation : ne plus voir un algorithme bio-inspiré comme une **boîte noire** qu'on invoque (et dont on ignore le mécanisme caché derrière une métaphore animale), mais comme une **composition de primitives** qu'on peut intercepter, lire et recomposer. Reconstruire WOA ou Equilibrium Optimizer à partir de `Match`, `IfElse` et de croisements géométriques, c'est *démontrer* leur mécanisme plutôt que le postuler ; les confronter sur des benchmarks sans trier les victoires (divergence sur Schwefel), c'est éprouver le No-Free-Lunch au lieu de le réciter ; appliquer la même grammaire à un TSP combinatoire puis à un relief terrestre réel, c'est prouver l'agnosticisme de la représentation. La leçon transversale : la puissance d'une métaheuristique ne réside pas dans sa métaphore (baleine, équilibre, essaim) mais dans les **briques réutilisables** qu'elle assemble — et les composer soi-même est précisément ce qui transforme un utilisateur de bibliothèque en praticien capable d'inventer la configuration adaptée à un paysage de fitness donné. + +## Liens + +- [Fork jsboige/MetaGeneticSharp](https://github.com/jsboige/MetaGeneticSharp) — code source, tests, ROADMAP +- [GeneticSharp PR #87](https://github.com/giacomelli/GeneticSharp/pull/87) — origine du projet (couche métaheuristiques 2020-2022) +- [Search-11-Metaheuristics](../Part1-Foundations/Search-11-Metaheuristics.ipynb) — introduction Python (PSO, ABC, SA, BRO) et benchmarks comparatifs +- [Série Search](../README.md) — vue d'ensemble diff --git a/MyIA.AI.Notebooks/Search/README.md b/MyIA.AI.Notebooks/Search/README.md index 46394330df..d24e3c52f0 100644 --- a/MyIA.AI.Notebooks/Search/README.md +++ b/MyIA.AI.Notebooks/Search/README.md @@ -622,7 +622,7 @@ Audit **disque ↔ CATALOG-STATUS ↔ prose** vérifié firsthand via `git ls-fi | **Part 1 — Fondements** (`Part1-Foundations/`) | **33** (**16 notebooks Python + Lean** : Search-1 → Search-11, Search-2b, 17b, Search-09b, Search-09c + **compagnon Lean Search-09d** (kernel `lean4-wsl`, lake `discrepancy_lean`) + **17 C#** : jumeaux `-Csharp` (Search-1 à 11 et 2b) + Search-2c QuikGraph natif + déclinaison deep-dive **Search-11b Métaheuristiques en 4 volets** C# natif, marathon #4956) | Python + Lean 4 + .NET (C#) | StateSpace, BFS/DFS/UCS/IDDFS, A*, Local Search (SA/Tabu), GA, Minimax/Alpha-Beta, MCTS, DLX, LP, Symbolic Automata, métaheuristiques (PSO/ABC/BRO + 160+ MEALPy), NetworkX, QuikGraph, minima fallacieux SDP (Burer–Monteiro), discrépance combinatoire (Beck–Fiala, Bansal–Jiang 2025) et sa formalisation Lean 4 (conjecture de Komlós) | | **Part 2 — Programmation par Contraintes** (`Part2-CSP/`) | **18** (9 Python : CSP-1 → CSP-9 + **9 jumeaux C#**, marathon #4956 achevé) | Python + .NET (C#) | CSP Fundamentals (backtracking), AC-3/FC/MAC, CSP Advanced (AllDifferent/Cumulative/Circuit), Scheduling (Job-Shop/RCPSP/Nurse), Optimization (Bin Packing/Knapsack), Hybridization (LCG/CP+SAT/CP+ML/LLM+CSP), Soft, Temporal (Allen's Interval Algebra), Distributed (Yokoo 1992) | | **Part 3 — Recherche heuristique avancée** (`Part3-Advanced/`) | **6** (3 Python : Search-12, 13, 14 + **3 jumeaux C#**) | Python + .NET (C#) | Pattern Databases (Korf & Felner 2002 additives), Limited Discrepancy Search (Harvey & Ginsberg 1995), Weighted A\* (Pohl 1970) — la discrépance combinatoire (ex-Search-17/18) vit désormais en Part 1 (Search-09c + compagnon Lean 09d) | -| **Part 4 — Métaheuristiques composables** (`Part4-Metaheuristics/`, C# .NET 9, MetaGeneticSharp) | **35** (MGS-1 → MGS-31 : cœur MGS-1..19, **trilogie MGS-7b/7c/7d** de projection N-D des paysages, MGS-17b sélection empirique, et le **volet comparatif vs MEALPY** MGS-20..31 — langage de composition, représentation vs algorithme, duels DE/SA/WOA/EO/FBI/BBPSO/GA vs Mealpy, ScatterSearch par décomposition, synthèse croisée ; tous C# .NET au-dessus de GeneticSharp vendored) | C# / .NET | Composition, Eukaryote, Islands, Compound Metaheuristics, TSP, projection N-D des paysages, Landscape Explorer, Center Bias, Island Synergy, Axis Alignment, Landscape Debias, Island Synergy Found, Landscape Analysis (FDC), Algorithm Selection (No-Free-Lunch), Parameter Control, CEC Banc, Metropolis Reinsertion, duels vs Mealpy | +| **Part 4 — Métaheuristiques composables** (`Part4-Metaheuristics/`, C# .NET 9, MetaGeneticSharp) | **35** (MGS-1 → MGS-31 : cœur MGS-1..19, **trilogie MGS-7b/7c/7d** de projection N-D des paysages, MGS-17b sélection empirique, **MGS-21** représentation vs algorithme ; le **volet comparatif vs MEALPY** (10 notebooks MGS-22..31) vit dans la sous-série [`Part4-Metaheuristics/MGS-vs-mealpy/`](Part4-Metaheuristics/MGS-vs-mealpy/README.md) — duels PSO/DE/SA/WOA/EO/FBI/BBPSO/GA/ScatterSearch vs Mealpy + synthèse croisée ; tous C# .NET au-dessus de GeneticSharp vendored) | C# / .NET | Composition, Eukaryote, Islands, Compound Metaheuristics, TSP, projection N-D des paysages, Landscape Explorer, Center Bias, Island Synergy, Axis Alignment, Landscape Debias, Island Synergy Found, Landscape Analysis (FDC), Algorithm Selection (No-Free-Lunch), Parameter Control, CEC Banc, Metropolis Reinsertion, représentation vs algorithme, [campagne comparative MGS vs mealpy](Part4-Metaheuristics/MGS-vs-mealpy/README.md) | | **Applications** (`Applications/`) | **50** (30 Python + 20 C# — **20 binômes Python ⇄ C#** App-1 à App-20, plus compagnons statistical-validity et jumeaux Python) | 30 Python + 20 C# | N-Queens, Graph Coloring, Nurse/Job-Shop/Timetabling Scheduling, Minesweeper, Wordle, MiniZinc, Picross (27M× speedup), Sports/Crossword/WFC CSP, SudokuBenchmark, Portfolio/TSP/VRP/Hyperparameter Tuning, Edge Detection, ConnectFour (Minimax/MCTS), Covering Arrays, Algorithm Selection | | **archive** (`archive/`) | **2** (CSPs_Intro, Exploration_non_informée_et_informée_intro, historiques pré-tranche 8/8 #5081) | Python | Notebooks historiques, remplacés par Part2-CSP/CSP-1-Fundamentals et Part1-Foundations/Search-{2,3} | | **Total** | **142** (33 + 18 + 6 + 35 + 50 = 142 pédagogiques, Search-09d inclus + 2 archive = 144) | Python + Lean 4 + C# | 5 piliers + archive, voir « Structure des fichiers » pour l'arborescence complète |