diff --git a/MyIA.AI.Notebooks/RL/rl_6_dqn_policy_gradient.ipynb b/MyIA.AI.Notebooks/RL/rl_6_dqn_policy_gradient.ipynb index e632bb24cb..6608cd154e 100644 --- a/MyIA.AI.Notebooks/RL/rl_6_dqn_policy_gradient.ipynb +++ b/MyIA.AI.Notebooks/RL/rl_6_dqn_policy_gradient.ipynb @@ -1263,14 +1263,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "d44982c0", - "metadata": {}, - "source": [ - "**Lecture chiffree — les finales croisees.** Les deux boucles d'entrainement de ce notebook finissent a 179.4 (DQN, 300 episodes) et 449.3 (REINFORCE, 400 episodes). Le resume qualitatif de la cellule suivante (« DQN : convergence plus reguliere ») est exact — mais le prix de cette regularite se lit dans ces deux finales : a budgets voisins, la methode a la variance la plus haute finit 2.5 fois plus haut sur CETTE execution. Une execution, un classement : la section 5 evaluera les deux politiques apprises en separation, et l'ablation de la section 3 a deja montre ce que 3 graines font a ce genre de classement.\n" - ] - }, { "cell_type": "markdown", "id": "t9k0e020", @@ -1381,14 +1373,6 @@ "print(f\"\\nSeuil CartPole-v1 (solve) : 475\")" ] }, - { - "cell_type": "markdown", - "id": "df0bfb6a", - "metadata": {}, - "source": [ - "**Lecture chiffree — l'evaluation finale contre le seuil.** `DQN : 188.3 +/- 14.4`, `REINFORCE : 247.7 +/- 12.6`, `Seuil CartPole-v1 (solve) : 475`. Trois lectures. (1) Personne ne resout l'environnement : les deux moyennes restent largement sous 475 (sur un maximum possible de 500). (2) Les barres ne se touchent pas : 188.3 + 14.4 = 202.7, en dessous de 247.7 - 12.6 = 235.1 — l'avance de REINFORCE sur cette evaluation est hors du bruit mesure. (3) Signal de coherence : la prose qui suit cite 488,6 et 209,0 — nombres absents de cette sortie commitee, ils decrivent une autre execution ; la lecture honnete se tient aux nombres imprimes ci-dessus, et le defaut de prose est signale a l'owner dans la PR.\n" - ] - }, { "cell_type": "markdown", "id": "w2n3e023", @@ -1403,13 +1387,11 @@ "tags": [] }, "source": [ - "**Le DQN atteint le seuil de résolution (475) sur CartPole-v1, REINFORCE pas.**\n", - "\n", - "Le DQN obtient une récompense moyenne de 488,6 (±25,8) et REINFORCE 209,0 (±41,7). Le DQN résout l'environnement (au-dessus du seuil 475) ; REINFORCE reste bien en dessous (~266 points sous le seuil). La différence s'explique par le *replay buffer* du DQN, qui rééchantillonne des transitions passées pour lisser l'estimation du gradient et stabiliser l'apprentissage — REINFORCE, qui n'utilise que les transitions de l'épisode courant, souffre d'une variance de gradient bien plus élevée.\n", + "**Lecture chiffree — l'evaluation finale contre le seuil.** `DQN : 188.3 +/- 14.4`, `REINFORCE : 247.7 +/- 12.6`, `Seuil CartPole-v1 (solve) : 475`.\n", "\n", - "Le DQN surpasse donc REINFORCE (488,6 vs 209,0) **avec une variance plus faible** (±25,8 vs ±41,7) : la conclusion qualitative (DQN plus stable que REINFORCE grâce au replay buffer) se confirme, et ici le DQN va jusqu'à résoudre l'environnement là où REINFORCE n'y parvient pas sur ce budget d'entraînement.\n", + "Trois lectures. (1) Personne ne resout l'environnement : les deux moyennes restent largement sous 475 (sur un maximum possible de 500). (2) Les barres ne se touchent pas : 188.3 + 14.4 = 202.7, en dessous de 247.7 - 12.6 = 235.1 — l'avance de REINFORCE sur cette evaluation est hors du bruit mesure. (3) Sur ce budget d'entrainement, la conclusion qualitative du notebook (le replay buffer et le target network stabilisent l'apprentissage, cf. l'ablation plus haut) reste vraie, mais elle ne se lit pas dans ces nombres : c'est REINFORCE qui domine ici.\n", "\n", - "> **Note de reproductibilité** : les résultats ci-dessus sont reproductibles (seed fixée, cell[2]). Sans seed, les récompenses dérivent fortement d'une exécution à l'autre — un écueil classique du RL. Les valeurs publiées dans la littérature CartPole-v1 (seuil 475, max 500) sont le point de référence.\n" + "> **Correction** : une version anterieure de cette lecture citait 488,6 et 209,0 et concluait que le DQN resout l'environnement. Ces nombres sont absents de la sortie commitee ci-dessus (ils decrivent une autre execution) : la lecture se tient desormais aux valeurs imprimees.\n" ] }, { @@ -1608,14 +1590,6 @@ "print(\"Exercice a completer : plage utile de target_update_freq\")" ] }, - { - "cell_type": "markdown", - "id": "7e4eac83", - "metadata": {}, - "source": [ - "**Lecture du stub — exercice 4, la plage utile de target_update_freq.** `Exercice a completer : plage utile de target_update_freq`. L'exercice demande de balayer la frequence de resynchronisation du target network — et l'ablation de la section 3 a deja donne la borne basse : retirer ENTIEREMENT le target network coute 2.4 points en moyenne (190.9 contre 188.5), un ecart noye dans un bruit inter-graines de plus ou moins 100. La question de l'exercice devient precise : existe-t-il une plage de frequences ou l'ecart SORT du bruit (resynchroniser trop rarement degenere vers le cas sans target), ou CartPole reste-t-il silencieux sur toute la plage ? Le protocole multi-graines de l'ablation, juste au-dessus, est le gabarit a reutiliser.\n" - ] - }, { "cell_type": "markdown", "id": "b7s8e028", diff --git a/MyIA.AI.Notebooks/RL/rl_6c_ppo_from_scratch.ipynb b/MyIA.AI.Notebooks/RL/rl_6c_ppo_from_scratch.ipynb index 4782bd49b0..1461da798b 100644 --- a/MyIA.AI.Notebooks/RL/rl_6c_ppo_from_scratch.ipynb +++ b/MyIA.AI.Notebooks/RL/rl_6c_ppo_from_scratch.ipynb @@ -934,14 +934,6 @@ " f\"{np.mean(curve[-50:]):7.1f}\")" ] }, - { - "cell_type": "markdown", - "id": "075341e1", - "metadata": {}, - "source": [ - "**Lecture chiffree — la graine 42 dans les deux protocoles.** Le run de la section 3.4 (400 episodes) termine a 495.2 ; la meme graine 42 dans l'ablation (300 episodes, sortie ci-dessus) termine a **158.2**. Meme algo, meme graine, budgets differents : l'ecart est le prix du budget court, un choix voulu par l'ablation (rendre la divergence visible pendant que les conditions apprennent encore). Deuxieme lecture, de coherence cette fois : les sections 3.6 et interpretation citent \"489.5\" puis \"489\" comme finale du run de reference — la sortie commitee imprime 495.2 ; l'ordre de grandeur tient, le chiffre exact de la prose ne se retrouve dans aucune sortie, ecart signale a l'owner dans la PR.\n" - ] - }, { "cell_type": "code", "execution_count": 9, @@ -1316,14 +1308,6 @@ "print(\"Exercice a completer\")\n" ] }, - { - "cell_type": "markdown", - "id": "88ec07e8", - "metadata": {}, - "source": [ - "**Lecture du stub — exercice 3, la comparaison A2C vs PPO.** `Exercice a completer`. La table de la section 5 donne les differences qualitatives (objectif, epochs par trajectoire, sensibilite au learning rate) ; l'exercice demande les courbes superposees qui les rendent visibles. Le gabarit methodologique est deja la, deux sections plus haut : l'ablation clipping vient de montrer ce qu'une graine unique cache (la graine 99 sauve la condition sans clipping avec 246.7 — le contre-exemple de la loterie). Comparer A2C et PPO sur UN run chacun reproduirait exactement le piege ; le protocole {42, 0, 1, 7, 99} x deux conditions est le gabarit a recopier, avec la mediane et l'IQR comme statistiques de rapport, comme dans la sortie d'ablation.\n" - ] - }, { "cell_type": "markdown", "id": "791b09fb", @@ -1451,4 +1435,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/MyIA.AI.Notebooks/RL/rl_6e_grpo_from_scratch.ipynb b/MyIA.AI.Notebooks/RL/rl_6e_grpo_from_scratch.ipynb index 812efbe2fb..deb4568c70 100644 --- a/MyIA.AI.Notebooks/RL/rl_6e_grpo_from_scratch.ipynb +++ b/MyIA.AI.Notebooks/RL/rl_6e_grpo_from_scratch.ipynb @@ -960,23 +960,6 @@ "print(\"Exercice 1 a completer : effet de la taille de groupe G sur la stabilite de l'avantage.\")\n" ] }, - { - "cell_type": "markdown", - "id": "12066577", - "metadata": { - "papermill": { - "duration": 0.002964, - "end_time": "2026-09-19T18:00:41.948640", - "exception": false, - "start_time": "2026-09-19T18:00:41.945676", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "**Lecture du stub — exercice 1, la variance de l'estimateur d'avantage.** `Exercice 1 a completer`. La mise a jour de la section 4 normalise chaque retour de groupe par $A_i = (R_i - \\bar{R}) / \\sigma_R$ avec G=6 : la moyenne ET l'ecart-type du groupe sont estimes sur 6 tirages seulement. C'est le talon d'Achille que l'exercice designe : a G=2, l'avantage des deux trajectoires ne depend plus que de laquelle finit devant l'autre — une piece pile-ou-face normalisee, quel que soit l'ecart reel ; a G=16 l'estimateur se stabilise mais chaque episode coute 16 rollouts. La grille a balayer, {2, 4, 8, 16}, encadre le G=6 courant des deux cotes — la sortie attendue est la variance du delta Sharpe cross-seed en fonction de G, et la question de l'enonce (un G minimal existe-t-il ?) se lit comme : en dessous de quel G la normalisation par groupe n'a-t-elle plus de sens statistique.\n" - ] - }, { "cell_type": "markdown", "id": "59d1de33", diff --git a/MyIA.AI.Notebooks/RL/rlpt_1_ppo_lm_rlhf.ipynb b/MyIA.AI.Notebooks/RL/rlpt_1_ppo_lm_rlhf.ipynb index 82c63d7d04..c08c213db7 100644 --- a/MyIA.AI.Notebooks/RL/rlpt_1_ppo_lm_rlhf.ipynb +++ b/MyIA.AI.Notebooks/RL/rlpt_1_ppo_lm_rlhf.ipynb @@ -609,7 +609,7 @@ "id": "601c97d3", "metadata": {}, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — courbes d'apprentissage sur 4 seeds\n", "\n", "Deux phénomènes complémentaires sont visibles sur les courbes :\n", "\n", @@ -685,7 +685,7 @@ "id": "8bd6e98b", "metadata": {}, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — mesure finale par prompt (seed 0)\n", "\n", "La mesure finale confirme l'alignement : le reward moyen atteint 1.00, `P('a'|A)` et `P('e'|B)` sont à 1.00\n", "après entraînement (contre ~0.08 avant RL), et les échantillons froids montrent des réponses conformes au prompt.\n", @@ -762,7 +762,7 @@ "id": "2bddc2e6", "metadata": {}, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — effet de beta (faible vs fort)\n", "\n", "La table montre le compromis dans sa forme **douce** : quand $\\beta$ passe de 0.05 à 2.0, la KL finale\n", "descend (0.67 → 0.41 → 0.28) — la politique reste d'autant plus proche de la référence que le KL coûte cher —\n", @@ -899,14 +899,6 @@ "print(\"Exercice a completer\")\n" ] }, - { - "cell_type": "markdown", - "id": "7ea69629", - "metadata": {}, - "source": [ - "**Lecture du stub — exercice 3, etendre la grille aux bornes.** `Exercice a completer`. La grille mesuree ci-dessus couvre beta de 0.05 a 2.0 : KL finale 0.67 -> 0.28, reward 1.00 dans les trois cas — multiplier la penalite KL par 40 n'a divise la derive que d'un facteur ~2.4. L'exercice demande les deux bornes extremes, 0.01 et 5.0. Avant d'executer, la grille permet d'ecrire la prediction qualitative : a 0.01 (cinq fois plus petit que le plus petit point), la KL finale devrait depasser 0.67 — la derive etait deja presque libre a 0.05 ; a 5.0 (2.5 fois le plus grand point), elle devrait passer sous 0.28. La vraie question n'est pas la, elle est dans la deuxieme colonne : le reward tiendra-t-il a 1.00 malgre tout ? Si oui, le compromis de ce toy confirme la lecture de la section 6 — beta regle le prix de la derive, pas la faisabilite de l'alignement. Executer le stub et confronter.\n" - ] - }, { "cell_type": "markdown", "id": "5376af59", @@ -962,4 +954,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/MyIA.AI.Notebooks/Search/Applications/CSP/App-19-ProceduralGeneration-WFC.ipynb b/MyIA.AI.Notebooks/Search/Applications/CSP/App-19-ProceduralGeneration-WFC.ipynb index ec22ee2943..8b3cbfcfdf 100644 --- a/MyIA.AI.Notebooks/Search/Applications/CSP/App-19-ProceduralGeneration-WFC.ipynb +++ b/MyIA.AI.Notebooks/Search/Applications/CSP/App-19-ProceduralGeneration-WFC.ipynb @@ -1,44 +1,44 @@ { "cells": [ - { - "cell_type": "markdown", - "id": "a6f90f7d", - "metadata": { - "papermill": { - "duration": 0.015981, - "end_time": "2026-06-03T00:09:51.793687+00:00", - "exception": false, - "start_time": "2026-06-03T00:09:51.777706+00:00", - "status": "completed" + { + "cell_type": "markdown", + "id": "a6f90f7d", + "metadata": { + "papermill": { + "duration": 0.015981, + "end_time": "2026-06-03T00:09:51.793687+00:00", + "exception": false, + "start_time": "2026-06-03T00:09:51.777706+00:00", + "status": "completed" + }, + "tags": [] }, - "tags": [] + "source": [ + "# App-19 — Génération procédurale de niveaux via WFC + CP-SAT\n", + "\n", + "_Application CSP : Wave Function Collapse (effondrement de fonction d'onde) modélisé avec OR-Tools CP-SAT. Adapté du projet étudiant EPITA Programmation par Contraintes 2026 (groupe H2)._\n", + "\n", + "## Objectifs du sujet\n", + "\n", + "| # | Objectif | Statut |\n", + "|---|----------|--------|\n", + "| 1 | Implémenter WFC comme CSP avec CP-SAT (variables=tuiles, contraintes=adjacence) | ✅ Cellule 3 |\n", + "| 2 | Contraintes globales : connectivité, chemin joueur, placement d'objets | ✅ Cellule 3 + 5 |\n", + "| 3 | Contraintes de difficulté (densité ennemis, variété) | ✅ Cellule 3 + 6 |\n", + "| 4 | Évaluation sur tilesets existants | ✅ Cellule 7 |\n", + "| 5 | Comparer qualité/diversité : WFC pur vs CP-SAT vs aléatoire | ✅ Cellule 8 |\n", + "\n", + "## Architecture\n", + "\n", + "```\n", + "Search/Applications/CSP/\n", + "├── wfc_cpsat.py — solveurs (Random, PureWFC, CP-SAT)\n", + "├── tileset.json — tileset donjon 5 tuiles\n", + "├── tileset_cave.json — tileset cave (plus complexe)\n", + "└── App-19-ProceduralGeneration-WFC.ipynb — ce fichier\n", + "```" + ] }, - "source": [ - "# App-19 — Génération procédurale de niveaux via WFC + CP-SAT\n", - "\n", - "_Application CSP : Wave Function Collapse (effondrement de fonction d'onde) modélisé avec OR-Tools CP-SAT. Adapté du projet étudiant EPITA Programmation par Contraintes 2026 (groupe H2)._\n", - "\n", - "## Objectifs du sujet\n", - "\n", - "| # | Objectif | Statut |\n", - "|---|----------|--------|\n", - "| 1 | Implémenter WFC comme CSP avec CP-SAT (variables=tuiles, contraintes=adjacence) | ✅ Cellule 3 |\n", - "| 2 | Contraintes globales : connectivité, chemin joueur, placement d'objets | ✅ Cellule 3 + 5 |\n", - "| 3 | Contraintes de difficulté (densité ennemis, variété) | ✅ Cellule 3 + 6 |\n", - "| 4 | Évaluation sur tilesets existants | ✅ Cellule 7 |\n", - "| 5 | Comparer qualité/diversité : WFC pur vs CP-SAT vs aléatoire | ✅ Cellule 8 |\n", - "\n", - "## Architecture\n", - "\n", - "```\n", - "Search/Applications/CSP/\n", - "├── wfc_cpsat.py — solveurs (Random, PureWFC, CP-SAT)\n", - "├── tileset.json — tileset donjon 5 tuiles\n", - "├── tileset_cave.json — tileset cave (plus complexe)\n", - "└── App-19-ProceduralGeneration-WFC.ipynb — ce fichier\n", - "```" - ] - }, { "cell_type": "markdown", "id": "a6f90f7d", @@ -788,21 +788,6 @@ "print(\"Exercice a completer : validation de niveau\")" ] }, - { - "cell_type": "markdown", - "id": "interp-validate", - "metadata": {}, - "source": [ - "### Lecture — le contrat de validation de l'exercice\n", - "\n", - "La cellule committée est le stub attendu : `violations: -1`, `valid: False`, les 4 étapes en commentaires `# Etape N`. Le stub ne lève aucune erreur (le notebook s'exécute de bout en bout, exercices non complétés compris) — c'est la convention de la série.\n", - "\n", - "Deux observations pour orienter la complétion :\n", - "\n", - "- Le seuil de validité demandé est **ambitieux** : `connectivity >= 0.5` alors que, dans la comparaison de la section 4, aucune des trois méthodes ne dépasse 7 %. Un `validate_level` correctement complété **rejettera** donc les trois grilles committées de ce notebook — c'est un test de non-régression utile : tout générateur amélioré qui passe ce seuil a réellement progressé.\n", - "- Tout le nécessaire est déjà importé en §0 : `adjacency_violations` et `bfs_reachable_floor` sont chargées dans la cellule d'imports. L'exercice est un assemblage de briques existantes, pas une réécriture." - ] - }, { "cell_type": "markdown", "id": "402d486d", diff --git a/MyIA.AI.Notebooks/Search/Applications/Hybrid/App-13-TSP-Metaheuristics.ipynb b/MyIA.AI.Notebooks/Search/Applications/Hybrid/App-13-TSP-Metaheuristics.ipynb index 7abbe0e4ec..c391aa537b 100644 --- a/MyIA.AI.Notebooks/Search/Applications/Hybrid/App-13-TSP-Metaheuristics.ipynb +++ b/MyIA.AI.Notebooks/Search/Applications/Hybrid/App-13-TSP-Metaheuristics.ipynb @@ -535,21 +535,6 @@ "tsp_medium.afficher(tournee_nn, f\"Plus Proche Voisin (cout={cout_nn:.2f})\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lecture du brute force TSP-10 (ancre sur code[2])\n", - "\n", - "La sortie verbatim de code[2] est `Solution optimale: 277.23 / Temps de calcul: 0.007s`. La cellule implemente `brute_force(tsp)` qui enumere toutes les permutations des villes (sauf la premiere fixee) et selectionne celle de cout minimal.\n", - "\n", - "**Pourquoi 0.007 s pour TSP-10** : `itertools.permutations(range(1, 10))` produit 9! = 362 880 permutations. En Python pur avec NumPy pour les calculs de distances, cela prend environ 7 millisecondes. C'est la borne haute de ce que la force brute peut faire en mode interactif.\n", - "\n", - "**Pourquoi fixer la ville 0** : eliminer les rotations (N solutions equivalentes par rotation) et les symetries miroir (2 solutions equivalentes par reflexion). Le facteur de reduction est 2N, soit 20 pour TSP-10. Le nombre de permutations effectivement evaluees est 9! / 2 = 181 440 (divise par 2 pour la symetrie miroir).\n", - "\n", - "**Implication pedagogique** : la force brute donne un cout **optimal** (277.23). C'est la **borne inferieure methodologique** : aucune autre methode ne peut faire mieux. Les methodes heuristiques qui suivent (NN, 2-opt, SA, GA, ACO) sont evaluees en comparaison de leur gap a cette borne." - ] - }, { "cell_type": "markdown", "id": "00770b17", @@ -2327,28 +2312,6 @@ "print('Fonction algorithme_genetique_hybride_tsp definie')" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lecture du 3-opt vs 2-opt (ancre sur code[17])\n", - "\n", - "La sortie verbatim de code[17] est `Cout initial (NN): 632.87 / Cout apres 2-opt: 553.98 / Cout apres 3-opt: ...`. La cellule implemente `three_opt(tournee, max_iterations)` qui :\n", - "- Prend une tournee amelioree par 2-opt.\n", - "- Applique une recherche 3-opt : remplace 3 aretes non adjacentes par 3 nouvelles aretes selon l'une des 8 topologies possibles (vs 1 pour 2-opt).\n", - "\n", - "**Pourquoi 3-opt est plus puissant** :\n", - "- 2-opt : 1 mouvement possible (inversion d'une sous-sequence).\n", - "- 3-opt : 8 mouvements possibles (combinaisons d'inversions et de permutations).\n", - "- L'espace de voisinage est plus large, donc la chance d'echapper aux minima locaux est plus grande.\n", - "\n", - "**Sortie observee** : sur TSP-15 (l'instance ATSP-12 ou similaire), 3-opt ameliore generalement le cout de 5-10 % par rapport a 2-opt. C'est substantiel mais au prix d'un temps de calcul plus long (complexite O(N^3) au lieu de O(N^2)).\n", - "\n", - "**Cas d'usage** : 3-opt est combine avec 2-opt dans les solveurs modernes (Lin-Kernighan). C'est la base du solveur Concorde pour les instances TSP < 1000 villes.\n", - "\n", - "**Note pedagogique** : le notebook introduit 3-opt comme extension naturelle de 2-opt. C'est une illustration classique de la complexite croissante en recherche locale : plus le voisinage est large, plus l'amelioration est grande, mais plus le temps de calcul est long." - ] - }, { "cell_type": "markdown", "id": "6ad8c972", @@ -2743,7 +2706,7 @@ "- **N = 200-1000** : OR-Tools ou LK-H.\n", "- **N > 1000** : solveurs specialises (Concorde, branch-and-bound parallele).\n", "\n", - "### Conclusion methodologique\n", + "### Taxonomie des methodes et critere de choix\n", "\n", "Le TSP illustre la **diversite des approches d'optimisation combinatoire** :\n", "1. **Methodes exactes** : explosion exponentielle, cas de petite taille.\n", diff --git a/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics.yaml b/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics.yaml index 83d00ee273..ead3cb51ba 100644 --- a/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics.yaml +++ b/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics.yaml @@ -6,6 +6,7 @@ bridge_verdict: SOTA-OK bridge_verdict_reason: "Python = OR-Tools constraint_solver routing (pywrapcp.RoutingModel + GLS Guided Local Search, OR-Tools 9.11) + numpy + matplotlib + itertools (22 cellules code). C# = Google.OrTools.ConstraintSolver (NuGet, C# binding du MEME engine OR-Tools 9.11) + Tranche 1 from-scratch BCL pure (System.*, 0 NuGet) PRESERVEE (11 cellules code). Verdict SOTA-OK (lib-vs-lib native-both) : les deux cotes invoquent le MEME moteur OR-Tools routing 9.11 (pywrapcp.RoutingModel <-> Google.OrTools.ConstraintSolver.RoutingModel). Prong-B (#3801) : discrimination metaheuristique vs exact (GLS ameliore significativement les couts vs nearest-neighbor from-scratch). Tranche 1 from-scratch preservee intacte (byte-identique a main). Python met l'accent sur SOTA + viz matplotlib + experimentation comparative ; C# demontre from-scratch + binding NuGet. parity_level: native-both preserve." known_differences: + - "2026-09-25 (PR #17054, myia-po-2025:CoursIA-2, redressement densite #17040) : retrait de 2 cellules markdown cote Python -- lectures redondantes ancrees sur les cellules code 17 et 2 (« Lecture du 3-opt vs 2-opt (ancre sur code[17]) », « Lecture du brute force TSP-10 (ancre sur code[2]) »). Verifie main vs tete : 22/22 cellules code byte-identiques (SHA des sources ET des outputs egaux), 22 code / 33 md -> 22 code / 31 md. Le twin C# n'a jamais porte ces deux cellules : la suppression ne fait que reduire une asymetrie, elle n'en cree aucune. --update en DERNIERE operation (cf #8957)." - "2026-09-13 (po-2026) #15949 volet 3/3 : encart hommage Stearns CONVERGENT -- une cellule markdown identique (id stearns-app13-py / stearns-app13-cs) inseree apres la cellule de titre des DEUX jumeaux : Lewis & Stearns 1968 a defini les grammaires LL(k) ; Stearns 1967 (regularity test for pushdown machines) : DPDA taille n -> DFA <= n^(n^(n^O(n))) ; premiere analyse de pire cas des heuristiques TSP (percage de toles GE). Cellules code byte-identiques, ordre et outputs intacts (markdown-only, exception C.2), validateur PASS. Drift CONTENT symetrique sur les DEUX cotes, correction CONVERGE la paire (precedents #11939, #15963). Rebaseline legitime par script, en DEUX temps : entree audit 2026-09-13 myia-po-2026:CoursIA (0011) attestant l'encart tel que livre au 1er commit du volet, puis (0012) apres le 2e commit du volet, qui a corrige la FORME du titre de l'encart (gardes markdown-rendering HINT-AS-HEADING / HEADING-IN-LIST) et a donc fait re-drifer la paire. Les shas COURANTS sont ceux de 0012 (blobs HEAD verifies) ; 0011 ne decrit plus les fichiers livres. --update en DERNIERE operation (cf #8957)." - '2026-08-31 : ATTESTATION UNILATERALE (PR #13659, lane myia-ai-01:CoursIA) -- reparation d''echappements JSON manges dans le markdown du cote C#. CAUSE : dans le .ipynb, la sequence dollar-\bot-dollar ecrite avec UN SEUL antislash est lue par le parseur JSON comme l''echappement \b (backspace, U+0008) ; la source chargee porte un caractere de controle et le notebook rend un dollar-ot-dollar prive de sa commande LaTeX. FIX : doubler l''antislash (\\bot). Le DRIFT est UNILATERAL parce que le DEFAUT l''est : la contrepartie App-13-TSP-Metaheuristics.ipynb (Python), 28 cellules markdown, a ete scannee sous controle positif (le litteral defectueux passe a json.loads doit rendre U+0008 -- assertion verifiee avant le scan) et ne porte AUCUN caractere de controle U+0008/U+000B/U+000C. Il n''y a donc rien a reparer de ce cote : l''attestation ne consacre aucune asymetrie de contenu. PORTEE DU DIFF cote repare (comparaison des JSON parses origin/main -> HEAD) : markdown uniquement, 0 cellule code touchee, 0 sortie modifiee, 0 execution_count deplace, 0 cellule ajoutee ou retiree.' - "Socle pedagogique commun : TSP / Voyageur de commerce (metaheuristiques + OR-Tools routing) comme application canonique. Les deux twins couvrent le meme socle theorique (formulation variables/domaines/contraintes, resolution, experimentation) avec parite semantique sur les concepts cibles." diff --git a/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0014-2026-09-25-myia-po-2025-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0014-2026-09-25-myia-po-2025-CoursIA-2.yaml new file mode 100644 index 0000000000..79efe84adb --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-13-tsp-metaheuristics/0014-2026-09-25-myia-po-2025-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-09-25' +by: myia-po-2025:CoursIA-2 +python_sha: c391aa537b2fc3fbb239231b13a07d11bf1d4264 +csharp_sha: d69acfcc63d794df027f2c44aef6056898f3d1f6 +content_python_sha: 8c0e7dc08313dcbdab064834fe4456966b62eb096305648f11c61ddc055e7d82 +content_csharp_sha: c9dfde30b57dac8e35090f6c0472b55e471ac9e250ef25123803ba7a743e30a4 diff --git a/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc.yaml b/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc.yaml index 9d22055723..fae0d01664 100644 --- a/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc.yaml +++ b/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc.yaml @@ -6,6 +6,7 @@ bridge_verdict: SOTA-OK bridge_verdict_reason: "Python = `wfc_cpsat` (module local qui wrappe `ortools` CP-SAT, moteur de production) + ipywidgets + matplotlib viz. C# = WFC from-scratch BCL pure (sections 1-8) + Tranche 2 : binding officiel **Google.OrTools CP-SAT** (NuGet 9.11.4210) portant le meme modele que le jumeau — adjacence par disjonction AddBoolOr, ratio sol 30-60 %, densite ennemis 5-20 %, comptes cles/coffres exacts, relaxation flow connectivite (source (0,0) forcee sol + arcs entrants), objectif variete via AddElement. Mesure 12x12 seed 42, instance identique au jumeau (cell 10) : 43 cases sol (30 %), 3 ennemis (7,0 % du sol), 1 cle, 1 coffre, connectivite BFS 7 % des cases sol (relaxation flow — meme ordre de grandeur que le ~7 % observe du jumeau), OPTIMAL ~1,5 s. Prong B : les contraintes globales (ratio, densite, comptes, connectivite) sont hors de portee du WFC pur (contraintes locales + backtracking) — le passage au solveur industriel fait valoir le moteur. parity_level: native-both : les deux cotes atteignent un moteur de production (OR-Tools CP-SAT)." known_differences: + - "2026-09-25 (PR #17054, myia-po-2025:CoursIA-2, redressement densite #17040) : retrait d'1 cellule markdown cote Python -- lecture redondante « Lecture — le contrat de validation de l'exercice ». Verifie main vs tete : 16/16 cellules code byte-identiques (SHA des sources ET des outputs egaux), 16 code / 29 md -> 16 code / 28 md. Le twin C# n'a jamais porte cette cellule : la suppression ne fait que reduire une asymetrie, elle n'en cree aucune. --update en DERNIERE operation (cf #8957)." - "2026-09-19 (PR #16218 suite, myia-po-2027:CoursIA) : restauration de la cellule d'intro (titre + objectifs + prerequis + duree) ecrasee par la cellule Hommage lors du fix plan-loss -- reinsertion verbatim de la cellule de origin/main AVANT l'hommage. 128 insertions pures, 0 suppression, outputs/execution_count intacts, plan-loss rc=0. drift Python (content) = reflete la reinsertion markdown, parite semantique inchangee (aucune cellule code touchee)." - "Socle pedagogique commun : Generation procedurale WFC / Wave Function Collapse (CSP + ipywidgets interactif) comme application canonique. Les deux twins couvrent le meme socle theorique (formulation variables/domaines/contraintes, resolution, experimentation) avec parite semantique sur les concepts cibles." - "Idiomes framework : Python = WFC + ipywidgets interactif + matplotlib GridSpec ; C# = BCL pure (System.Text) pour le from-scratch (sections 1-8) + Google.OrTools CP-SAT (Tranche 2)." diff --git a/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0011-2026-09-25-myia-po-2025-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0011-2026-09-25-myia-po-2025-CoursIA-2.yaml new file mode 100644 index 0000000000..e54a924b4f --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/app-19-proceduralgeneration-wfc/0011-2026-09-25-myia-po-2025-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-09-25' +by: myia-po-2025:CoursIA-2 +python_sha: 8b3cbfcfdf53b1cc45d84a0e721f500ab9c03766 +csharp_sha: 4784f200cb1ca7247a27846c8df0af4682ec20d8 +content_python_sha: 4ea7e0827c9b334a0a04e687a3f4a5e1a1ff206b0b93417347fde1c5ee7d609a +content_csharp_sha: 365da44d73ef9551d9732edd40ad7cdfef4771b55a28a51a0dce984c18ef4550