diff --git a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb index 80d9fe6668..a5529cb8ce 100644 --- a/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb +++ b/MyIA.AI.Notebooks/Search/Part4-Metaheuristics/MGS-vs-mealpy/MGS-28-BareBonesPSO-vs-Mealpy.ipynb @@ -16,7 +16,7 @@ "\n", "MGS-27 a refermé la question FBI sur la paire qui prétendait le moins à la différence : le port C# dérivé battait sa référence mealpy des deux mains. La paire 7 descend d'un cran encore dans la prétention — et change de nature : le **Bare Bones PSO** de Kennedy (2003) est le PSO dépouillé de toute sa mécanique, ni inertie *w*, ni coefficients *c1*/*c2* : chaque gène de la nouvelle particule est un simple **tirage gaussien** autour du milieu entre le meilleur personnel et le meilleur global. Deux conséquences structurelles gouvernent ce protocole :\n", "\n", - "1. **Aucun PSO de mealpy 3.0.2 n'est bare-bones** — les sept variantes du module (`OriginalPSO`, `P_PSO`, `C_PSO`, `CL_PSO`, `AIW_PSO`, `HPSO_TVAC`, `LDW_PSO`) portent toutes les constantes de vitesse du PSO classique ; en prendre une pour jumeau serait mesurer un **PSO classique déguisé** en bare-bones. Le jumeau mealpy est donc un *subclass* de `Optimizer` — le point d'extension natif de la bibliothèque — qui **pinne la formule de Kennedy** dans le harnais mealpy (graine, comptage d'évaluations, correction de bornes).\n", + "1. **Aucun PSO de mealpy 3.0.2 n'est bare-bones** — les sept variantes du module (`OriginalPSO`, `P_PSO`, `C_PSO`, `CL_PSO`, `AIW_PSO`, `HPSO_TVAC`, `LDW_PSO`) conservent toutes une **vitesse explicite** et un couple de coefficients de vitesse — constantes *w*/*c1*/*c2* (ou leurs variantes `w_min`/`w_max`/`ci`/`cf`/`c_local`) pour six d'entre elles, coefficients sin/cos dynamiques pour `P_PSO` ; en prendre une pour jumeau serait mesurer un **PSO classique déguisé** en bare-bones. Le jumeau mealpy est donc un *subclass* de `Optimizer` — le point d'extension natif de la bibliothèque — qui **pinne la formule de Kennedy** dans le harnais mealpy (graine, comptage d'évaluations, correction de bornes).\n", "2. **Le portage MGS est ancré sur la position courante, pas sur le pbest** — le framework géométrique n'expose pas de mémoire *pbest_i* par particule, et l'écart est documenté *in-source* dans `BareBonesParticleSwarm.cs`. Pour distinguer l'écart **noyau** (moteur contre moteur) de l'écart **d'ancrage** (sémantique du portage), le bench croise donc **trois bras** : le composé MGS, la variante mealpy alignée sur sa sémantique, et le Kennedy 2003 littéral.\n", "\n", "La grille, la représentation R1, le budget (population 50, 160 générations) et les graines {0, 1, 7, 42} sont ceux des paires précédentes : les médianes se lisent dans la même colonne du tableau croisé de l'Epic.\n" @@ -34,6 +34,112 @@ "execution_count": 1, "metadata": {}, "outputs": [ + { + "output_type": "display_data", + "data": { + "text/html": [ + "\r\n", + "
\r\n", + " \r\n", + " \r\n", + "
" + ] + }, + "metadata": {} + }, { "output_type": "stream", "name": "stdout", @@ -45,9 +151,9 @@ "source": [ "// === MGS-28 : socle commun — DLLs MGS, grille de référence, fonction de coût ===\n", "// Même socle que MGS-22/23 : la représentation R1 (continu + arrondi) est le substrat du bench.\n", - "#r \"../MetaGeneticSharp/src/MetaGeneticSharp.Domain/bin/Debug/net9.0/GeneticSharp.Infrastructure.Framework.dll\"\n", - "#r \"../MetaGeneticSharp/src/MetaGeneticSharp.Domain/bin/Debug/net9.0/MetaGeneticSharp.Infrastructure.dll\"\n", - "#r \"../MetaGeneticSharp/src/MetaGeneticSharp.Domain/bin/Debug/net9.0/MetaGeneticSharp.Domain.dll\"\n", + "#r \"../../MetaGeneticSharp/src/MetaGeneticSharp.Domain/bin/Debug/net9.0/GeneticSharp.Infrastructure.Framework.dll\"\n", + "#r \"../../MetaGeneticSharp/src/MetaGeneticSharp.Domain/bin/Debug/net9.0/MetaGeneticSharp.Infrastructure.dll\"\n", + "#r \"../../MetaGeneticSharp/src/MetaGeneticSharp.Domain/bin/Debug/net9.0/MetaGeneticSharp.Domain.dll\"\n", "using MetaGeneticSharp;\n", "using GeneticSharp;\n", "using System.Diagnostics;\n", @@ -112,7 +218,7 @@ "source": [ "**Lecture.** Le socle est posé, identique à MGS-23 au nom près — c'est voulu : la comparabilité\n", "des paires de l'Epic repose sur un protocole strictement apparié (même grille Easy[0], même\n", - "représentation R1 continue à 51 gènes, même fonction de coût comptée en conflits, renvoyant 0\n", + "représentation R1 continue à 36 gènes, même fonction de coût comptée en conflits, renvoyant 0\n", "ssi la grille est résolue). Le pont PythonNet qui suivra réimplémente ce comptage *à\n", "l'identique* et le vérifie sur des vecteurs témoins déterministes : la seule différence\n", "mesurable entre les bras sera donc le moteur, pas l'échelle de la fitness.\n" @@ -127,7 +233,7 @@ "output_type": "stream", "name": "stdout", "text": [ - "MGS BBPSO (graine 7, témoin) : 29 conflits, 8000 évaluations, 327 ms, checkpoints 25/50/75/100 % = 29/29/29/29.\r\n" + "MGS BBPSO (graine 7, témoin) : 29 conflits, 8000 évaluations, 291 ms, checkpoints 25/50/75/100 % = 29/29/29/29.\r\n" ] } ], @@ -234,18 +340,18 @@ "outputs": [ { "output_type": "display_data", - "metadata": {}, "data": { "text/html": [ "
Installing Packages
" ] - } + }, + "metadata": {} }, { "output_type": "stream", "name": "stdout", "text": [ - "Pont PythonNet actif : mealpy 3.0.2 sur Python 3.13.3\r\n" + "Pont PythonNet actif : mealpy 3.0.2 sur Python 3.13.12\r\n" ] }, { @@ -496,8 +602,10 @@ "source": [ "**Lecture.** Le pont est actif et la sanity check porte tout le bench : la fonction de coût\n", "Python redonne *exactement* le comptage C# sur les vecteurs témoins déterministes. Le point\n", - "structurant est le **subclass `OriginalBBPSO`** : mealpy n'offre aucun PSO bare-bones (les\n", - "sept variantes du module portent toutes *w*/*c1*/*c2*), et le point d'extension officiel de la\n", + "structurant est le **subclass `OriginalBBPSO`** : mealpy n'offre aucun PSO bare-bones (six des sept\n", + "variantes du module exposent explicitement *w*/*c1*/*c2* — ou leurs variantes\n", + "`w_min`/`w_max`/`ci`/`cf`/`c_local` — et la septième, `P_PSO`, porte des coefficients\n", + "sin/cos dynamiques sur la même mise à jour de vitesse), et le point d'extension officiel de la\n", "bibliothèque est précisément la classe `Optimizer` — le jumeau hérite donc du harnais mealpy\n", "complet (générateur seedé par `solve(prob, seed=...)`, comptage d'évaluations par `Problem`,\n", "correction de bornes `correct_solution`, suivi `g_best`) en pinnant la formule de Kennedy.\n", @@ -569,7 +677,9 @@ "// d'ancre et de sélection pour que l'écart mesuré s'interprète (noyau vs portage), pas le subir.\n", "using (Py.GIL())\n", "{\n", - " // 1) La détection Clerc : aucun PSO mealpy 3.0.2 n'est bare-bones — tous portent w/c1/c2.\n", + " // 1) La détection Clerc : aucun PSO mealpy 3.0.2 n'est bare-bones — six portent w/c1/c2\n", + " // (ou leurs variantes w_min/w_max/ci/cf/c_local) ; P_PSO porte des coefficients\n", + " // sin/cos dynamiques sur la même mise à jour de vitesse.\n", " S28.Exec(@\"__pso_catalog__ = ''\n", "for _cls in (OriginalPSO, P_PSO, C_PSO, CL_PSO, AIW_PSO, HPSO_TVAC, LDW_PSO):\n", " _m = _cls(epoch=10, pop_size=5)\n", @@ -613,9 +723,12 @@ "écart MGS↔mealpy sur cette paire serait **ininterprétable** — il mêlerait le moteur (C#\n", " GéneticSharp + composé géométrique contre NumPy + harnais mealpy) et la sémantique du\n", "portage (ancre courante contre *pbest*, glouton pool contre per-particle contre remplacement\n", - "inconditionnel). Le catalogue de la cellule établit la **détection Clerc** : les sept PSO\n", - "mealpy portent tous des constantes de vitesse — aucun ne prétend au bare-bones, et le\n", - "subclass est la seule voie honnête vers un jumeau. La propriété de gel (écart-type nul ⇒\n", + "inconditionnel). Le catalogue de la cellule établit la **détection Clerc** : six des sept PSO\n", + "mealpy exposent explicitement les constantes de vitesse (*w*/*c1*/*c2* ou leurs\n", + "variantes), et le septième, `P_PSO`, porte des coefficients sin/cos dynamiques sur la\n", + "même mise à jour de vitesse — **aucun** ne prétend au bare-bones (la sortie le montre :\n", + "la ligne `P_PSO` est la seule à ne lister aucun paramètre), et le subclass est la seule\n", + "voie honnête vers un jumeau. La propriété de gel (écart-type nul ⇒\n", "tirage déterministe) est le comportement littéral de Kennedy : l'élite ne bouge pas tant\n", "qu'elle est le gbest, et c'est une **propriété**, pas un bug à corriger — l'Exercice 2 en\n", "mesurera le prix.\n" @@ -630,14 +743,14 @@ "output_type": "stream", "name": "stdout", "text": [ - "mealpy BBPSO-kennedy (graine 7, témoin) : 26 conflits, 8050 évaluations, 600 ms.\r\n" + "mealpy BBPSO-kennedy (graine 7, témoin) : 26 conflits, 8050 évaluations, 548 ms.\r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy BBPSO-mgs (graine 7, témoin) : 26 conflits, 8050 évaluations, 539 ms.\r\n" + "mealpy BBPSO-mgs (graine 7, témoin) : 26 conflits, 8050 évaluations, 480 ms.\r\n" ] }, { @@ -694,84 +807,84 @@ "output_type": "stream", "name": "stdout", "text": [ - "MGS 0 31 8000 292 0,036 33/31/31/31 \r\n" + "MGS 0 31 8000 200 0,025 33/31/31/31 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "MGS 1 31 8000 289 0,036 31/31/31/31 \r\n" + "MGS 1 31 8000 204 0,025 31/31/31/31 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "MGS 7 29 8000 302 0,038 29/29/29/29 \r\n" + "MGS 7 29 8000 191 0,024 29/29/29/29 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "MGS 42 30 8000 283 0,035 30/30/30/30 \r\n" + "MGS 42 30 8000 212 0,027 30/30/30/30 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-mgs 0 19 8050 562 0,070 32/22/20/19 \r\n" + "mealpy-mgs 0 19 8050 532 0,066 32/22/20/19 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-mgs 1 25 8050 567 0,070 31/26/25/25 \r\n" + "mealpy-mgs 1 25 8050 515 0,064 31/26/25/25 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-mgs 7 26 8050 579 0,072 32/26/26/26 \r\n" + "mealpy-mgs 7 26 8050 529 0,066 32/26/26/26 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-mgs 42 27 8050 631 0,078 32/30/28/27 \r\n" + "mealpy-mgs 42 27 8050 539 0,067 32/30/28/27 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-kennedy 0 19 8050 793 0,098 32/22/20/19 \r\n" + "mealpy-kennedy 0 19 8050 540 0,067 32/22/20/19 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-kennedy 1 25 8050 667 0,083 31/26/25/25 \r\n" + "mealpy-kennedy 1 25 8050 570 0,071 31/26/25/25 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-kennedy 7 26 8050 826 0,103 32/26/26/26 \r\n" + "mealpy-kennedy 7 26 8050 582 0,072 32/26/26/26 \r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-kennedy 42 27 8050 724 0,090 32/30/28/27 \r\n" + "mealpy-kennedy 42 27 8050 577 0,072 32/30/28/27 \r\n" ] }, { @@ -785,21 +898,21 @@ "output_type": "stream", "name": "stdout", "text": [ - "MGS : médiane conflits 30,5 (min 29, max 31), ms/éval moyen 0,036\r\n" + "MGS : médiane conflits 30,5 (min 29, max 31), ms/éval moyen 0,025\r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-mgs : médiane conflits 25,5 (min 19, max 27), ms/éval moyen 0,073\r\n" + "mealpy-mgs : médiane conflits 25,5 (min 19, max 27), ms/éval moyen 0,066\r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "mealpy-kennedy : médiane conflits 25,5 (min 19, max 27), ms/éval moyen 0,093\r\n" + "mealpy-kennedy : médiane conflits 25,5 (min 19, max 27), ms/éval moyen 0,070\r\n" ] }, { @@ -813,7 +926,7 @@ "output_type": "stream", "name": "stdout", "text": [ - "ECART NOYAU (bras1 - bras2, sémantique alignée) : médianes 30,5 vs 25,5, ms/éval 0,50x\r\n" + "ECART NOYAU (bras1 - bras2, sémantique alignée) : médianes 30,5 vs 25,5, ms/éval 0,38x\r\n" ] }, { @@ -827,7 +940,7 @@ "output_type": "stream", "name": "stdout", "text": [ - "ECART BRUT (bras1 - bras3, lecture des paires) : médianes 30,5 vs 25,5, ms/éval 0,39x\r\n" + "ECART BRUT (bras1 - bras3, lecture des paires) : médianes 30,5 vs 25,5, ms/éval 0,36x\r\n" ] }, { @@ -1027,21 +1140,21 @@ "output_type": "stream", "name": "stdout", "text": [ - " C# : 4,1 ms total -> 0,008 ms/éval\r\n" + " C# : 3,1 ms total -> 0,006 ms/éval\r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - " Python : 18,8 ms total -> 0,038 ms/éval\r\n" + " Python : 19,3 ms total -> 0,039 ms/éval\r\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - " rapport Python/C# : 4,59x\r\n" + " rapport Python/C# : 6,30x\r\n" ] } ], @@ -1086,8 +1199,8 @@ "\n", "- **Classement** : les deux jumeaux mealpy ex æquo en tête (médiane 25,5 conflits chacun), MGS troisième (30,5). L'écart brut de 5 conflits est donc imputable au moteur, pas au portage.\n", "- **Écart d'ancrage nul — la paire la plus propre de l'Epic** : les deux jumeaux mealpy (ancre `local_solution` = pbest contre ancre `solution` = position courante, remplacement inconditionnel contre glouton) produisent des trajectoires **identiques graine par graine** — mêmes conflits finaux et mêmes checkpoints sur les 4 graines (écarts `[0,0,0,0]` partout). La divergence tranchée dans la cellule formules ne change rien ici : sur ce problème, la mise à jour locale gloutonne confond pbest et position courante dès qu'une particule s'améliore.\n", - "- **Écart noyau réel, 5 conflits pour mealpy** : à sémantique strictement alignée (le bras mealpy-mgs porte exactement la formule MGS dans le harnais mealpy), mealpy atteint 25,5 contre 30,5 — la différence vient du moteur (harnais mealpy : évaluation initiale de la population, `update_global_best` post-epoch), pas des équations. La forme le confirme : MGS est devant ou égal au premier quart (checkpoints 29-33 contre 31-32), puis mealpy creuse l'écart de mi-course à la fin — graine 0 persistante `[1,9,11,12]`, graines 1/7/42 en croisement. Concrètement, mealpy continue d'exploiter en fin de course (20→19 et 28→27 entre 75 % et 100 %) quand MGS est figé dès le premier quart (cp25 = cp100 sur 3 graines sur 4) — la propriété de **gel** de la cellule formules, visible dans la sortie.\n", - "- **Vitesse** : MGS reste 2× moins cher par évaluation (0,036 contre 0,073 ms/éval, ratio 0,50×) et la fitness C# isolée est 4,59× plus rapide — mais le budget est apparié (8 000/8 050 évaluations), donc mealpy gagne à budget égal. C'est le profil inversé du FBI (MGS-27) : là-bas le portage dérivait et gagnait des deux mains ; ici le portage est fidèle, ne dérive pas — et c'est le harnais adverse qui paie la qualité.\n", + "- **Écart noyau réel, 5 conflits pour mealpy** : à sémantique strictement alignée (le bras mealpy-mgs porte exactement la formule MGS dans le harnais mealpy), mealpy atteint 25,5 contre 30,5 — la différence vient du moteur (harnais mealpy : évaluation initiale de la population, `update_global_best` post-epoch), pas des équations. La forme le confirme, mais **pas uniformément selon la graine** : au premier quart MGS mène sur deux graines (7 : 29 contre 32 ; 42 : 30 contre 32) et fait jeu égal sur la graine 1 (31 contre 31), mais il est **déjà derrière sur la graine 0** (33 contre 32) — le profil de cette graine est *persistant* (delta `[1,9,11,12]`, l'écart s'installe et grandit), là où les graines 1/7/42 sont classées *mixtes* (`[0,5,6,6]`, `[-3,3,3,3]`, `[-2,0,2,3]` : MGS repasse derrière mealpy au plus tard au troisième quart, après avoir été devant ou à égalité au premier). Concrètement, mealpy continue d'exploiter en fin de course (20→19 et 28→27 entre 75 % et 100 %) quand MGS est figé après le premier quart — `cp25 = cp100` sur 3 graines sur 4, la graine 0 plaçant sa seule amélioration entre 25 % et 50 % — la propriété de **gel** de la cellule formules, visible dans la sortie.\n", + "- **Vitesse** : MGS reste environ deux fois moins cher par évaluation — le rapport `ms/éval` de ce passage kernel (0,38×) est lu dans la cellule de bench, et la fitness C# isolée reste plus rapide d'un facteur du même ordre (rapport Python/C# : 6,30× dans la cellule de coût par évaluation). Ce sont des mesures **machine** : les valeurs absolues ne sont donc pas recopiées ici, seuls les rapports le sont — et ces rapports eux-mêmes varient d'un passage kernel à l'autre ; le verdict ne repose pas sur eux — mais le budget est apparié (8 000/8 050 évaluations), donc mealpy gagne à budget égal. C'est le profil inversé du FBI (MGS-27) : là-bas le portage dérivait et gagnait des deux mains ; ici le portage est fidèle, ne dérive pas — et c'est le harnais adverse qui paie la qualité.\n", "- **Fil rouge PSO de l'Epic** : MGS-22 (PSO classique à coefficients) donnait mealpy devant en qualité à ex æquo en vitesse ; MGS-28 (BBPSO, zéro coefficient) resserre la démonstration — dépouiller la particule de w/c1/c2 ne change pas le verdict moteur, il l'isole : tout ce qui reste de l'écart est noyau." ] }, @@ -1255,6 +1368,64 @@ "\n", "Console.WriteLine(\"Exercice a completer (decommentez le bloc ci-dessus).\");\n" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Diagnostic dérive\n", + "\n", + "**Cause (a) — environnement / résolution de chemin (#13959).** Les trois directives `#r` de la cellule\n", + "socle pointaient `../MetaGeneticSharp/...`, une profondeur de répertoire calculée quand ce\n", + "notebook vivait à la racine de `Part4-Metaheuristics/`. L'isolation des face-à-face\n", + "MGS ↔ mealpy dans la sous-série `MGS-vs-mealpy/` (#13959, déplacement `R100`) a ajouté un\n", + "niveau d'arborescence : `../MetaGeneticSharp` ne résolvait plus rien, la cellule socle ne\n", + "compilait plus, et les sorties — transportées telles quelles par le déplacement, jamais\n", + "re-confirmées par un run — se sont figées.\n", + "\n", + "**Correctif.** Les trois directives passent à `../../MetaGeneticSharp/...` (mêmes DLLs\n", + "`net9.0` Debug, même gitlink `78ce550`) et le notebook est ré-exécuté de bout en bout au\n", + "kernel `.net-csharp` réel, pont PythonNet vers mealpy 3.0.2. Aucune sortie n'est éditée à la\n", + "main.\n", + "\n", + "**Contradictions prose ↔ sorties, pré-existantes, corrigées dans le même passage.** Elles ont\n", + "survécu au gel des sorties précisément parce qu'aucun run ne les confrontait plus :\n", + "\n", + "- la lecture du socle annonçait une représentation R1 à `51 gènes` alors que la sortie du socle\n", + " en compte **36** (36 cellules vides, 45 indices fixes, 36 gènes) ;\n", + "- la lecture du croisement annonçait les graines 1/7/42 *en croisement* alors que le classifieur\n", + " imprimé les donne **mixtes** (et la graine 0 *persistante*), surestimait la position de MGS au\n", + " premier quart — MGS y est **déjà derrière sur la graine 0** (33 conflits contre 32) — et\n", + " recopiait des temps muraux absolus ;\n", + "- l'introduction et la lecture de la cellule formules affirmaient que **les sept** PSO mealpy\n", + " portent les constantes *w*/*c1*/*c2*, ce que le catalogue imprimé contredit pour `P_PSO`\n", + " (aucun paramètre listé). Vérifié in-source : `P_PSO` porte des coefficients sin/cos dynamiques,\n", + " pas les constantes de Clerc. La conclusion (« aucun n'est bare-bones ») tient ; la raison\n", + " invoquée est corrigée.\n", + "\n", + "**Verdict C.4 : `CAUSE_FIXED`.** Protocole inchangé — graines `{0, 1, 7, 42}`, population 50,\n", + "160 générations/epochs, 8 000 évaluations (MGS) / 8 050 (mealpy), représentation R1, fonction\n", + "de coût en conflits, checkpoints 25/50/75/100 %. Sur **sept** exécutions complètes — trois par\n", + "le moteur d'exécution (`dotnet_executor.py`), quatre par le wrapper canonique de la famille\n", + "(`exec_dotnet_persist.py`), la dernière fournissant les sorties committées — les grandeurs\n", + "déterministes — conflits finaux par graine, checkpoints, budget d'évaluations, drapeau `12/12`\n", + "bras-graines stables — sont **exactes et identiques** entre elles et à celles déjà committées :\n", + "la non-régression est **mesurée**, pas supposée. Seuls les temps muraux varient d'un passage\n", + "kernel à l'autre ; ils sont conservés en **rapport**, jamais en valeur absolue.\n", + "\n", + "**Verdict de performance : `NO IMPROVEMENT`.** Sur la taxonomie fermée `IMPROVES` /\n", + "`NO IMPROVEMENT` / `TRADE-OFF` / `INCONCLUSIVE`, ce grain vaut `NO IMPROVEMENT` : l'axe performance\n", + "est une **invariance mesurée contre le moteur mis à jour** — protocole, graines, budget\n", + "d'évaluations et fonction de coût sont identiques d'un bout à l'autre, mais les sorties\n", + "committées sortent d'un moteur reconstruit (`net9.0` Debug) et non de celui qui avait produit\n", + "les sorties gelées : l'égalité est **constatée** run après run, jamais déduite du seul\n", + "protocole. Seul le chemin de résolution des directives `#r` est corrigé. Le livrable n'est donc pas\n", + "un gain de performance\n", + "mais l'**exécutabilité restaurée** — cellule socle de nouveau compilable, notebook entier\n", + "relançable au kernel `.net-csharp` réel — assortie d'une **non-régression mesurée**. Les deux\n", + "verdicts coexistent sans se contredire : `CAUSE_FIXED` qualifie la cause de la dérive (fixée),\n", + "`NO IMPROVEMENT` qualifie l'axe performance (inchangé)." + ] } ], "metadata": {