From eb52e61a6434f3c961a3cde0cb74e45d924de84d Mon Sep 17 00:00:00 2001 From: jsboige Date: Wed, 2 Sep 2026 18:55:51 +0200 Subject: [PATCH 1/2] enrich(csp,#11601): CSP-4-Scheduling-Csharp density 1221 -> 1649 Round-2 density tranche (markdown-only, target >=1500): 3 "Lecture du planning" interpretation cells anchored on the REAL solver outputs of the JSSP / RCPSP / Nurse sections (machine-bottleneck and interaction-bound reading of makespan 11, critical-path reading of makespan 10, double- saturation reading of 42 shifts). One md ref fix: "cellules 6, 8 et 10" -> "sections 1, 2 et 3" (future-proof against insertions). Rendering 0 violations, interp positioning 0 findings, accents audit numeric (195->282, untouched cells identical), code cells and outputs untouched. Co-Authored-By: Claude-Code --- .../Part2-CSP/CSP-4-Scheduling-Csharp.ipynb | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/MyIA.AI.Notebooks/Search/Part2-CSP/CSP-4-Scheduling-Csharp.ipynb b/MyIA.AI.Notebooks/Search/Part2-CSP/CSP-4-Scheduling-Csharp.ipynb index dec6fbb66c..75ec7aa828 100644 --- a/MyIA.AI.Notebooks/Search/Part2-CSP/CSP-4-Scheduling-Csharp.ipynb +++ b/MyIA.AI.Notebooks/Search/Part2-CSP/CSP-4-Scheduling-Csharp.ipynb @@ -253,6 +253,22 @@ "}\n" ] }, + { + "cell_type": "markdown", + "id": "c9d5e0a1", + "metadata": {}, + "source": [ + "**Lecture du planning JSSP** (cellule ci-dessus) :\n", + "\n", + "Le solveur confirme le **makespan optimal = 11 unités** annoncé en tête de cellule, et le planning détaillé permet de lire *pourquoi* 11 :\n", + "\n", + "- **M1 est la machine goulot** : elle enchaîne Job 2 [0→4], Job 0 [4→6] puis Job 1 [6→10], soit 10 unités de charge sur 11 — une seule unité d'inactivité, en fin d'horizon. M0 (charge 5) et M2 (charge 6) sont largement sous-utilisées.\n", + "- **Les chaînes de jobs ne suffisent pas à expliquer l'optimum** : chaque job somme à 7 unités (3+2+2, 2+1+4, 4+3) — la borne « chaîne » vaut 7, la borne « charge machine » vaut 10 (M1). L'optimum 11 dépasse ces deux bornes prises séparément : c'est leur *interaction* qui le fixe.\n", + "- **L'unité décisive se lit sur M2** : la dernière opération de Job 0 (M2, 2 u) ne peut démarrer ni avant la fin de Job 0 Op 1 (t = 6), ni avant la libération de M2 — occupée par Job 1 Op 1 [5→6] puis Job 2 Op 1 [6→9]. D'où le créneau [9→11], et le makespan 11.\n", + "\n", + "C'est exactement le rôle d'une contrainte globale `AddNoOverlap` : le solveur raisonne nativement sur les disjonctions *par machine* (paires d'intervalles), là où une modélisation naïve énumérerait O(n²) inégalités binaires par machine." + ] + }, { "cell_type": "markdown", "id": "d0a780bb", @@ -365,6 +381,20 @@ "}\n" ] }, + { + "cell_type": "markdown", + "id": "b8e4d1f0", + "metadata": {}, + "source": [ + "**Lecture du planning RCPSP** (cellule ci-dessus) :\n", + "\n", + "Le **makespan optimal = 10 unités** se lit comme la longueur du **chemin de précédence critique** : T0 [0→2] → T2 [2→6] → T4 [6→9] → T5 [9→10] cumule exactement 2 + 4 + 3 + 1 = 10 unités. Aucun planning ne peut raccourcir cette chaîne : 10 est une borne inférieure atteinte — l'instance est **contrainte par les précédences, pas par les ressources**.\n", + "\n", + "Les deux tâches hors chemin critique vivent dans la marge : T1 [2→5] se glisse en parallèle de T2, et T3 [5→7] démarre dès la fin de son prédécesseur T1. Le détail fin : sur la fenêtre [2→5], la ressource R0 est **exactement saturée** (T1 consomme 1, T2 consomme 3, capacité 4) — le couplage précédence × ressource est visible dans la sortie, sans pour autant allonger le makespan au-delà du chemin critique.\n", + "\n", + "C'est la lisibilité propre au RCPSP : la contrainte globale `AddCumulative` (cumul par instant) laisse le raisonnement chronologique au premier plan, et le builder fluent `AddCumulative(capacity).AddDemands(intervals, demands)` exprime chaque ressource en une seule ligne." + ] + }, { "cell_type": "markdown", "id": "05516294", @@ -490,6 +520,23 @@ "}\n" ] }, + { + "cell_type": "markdown", + "id": "a7f3c2e9", + "metadata": {}, + "source": [ + "**Lecture du planning Nurse** (cellule ci-dessus) :\n", + "\n", + "L'optimum **42 shifts** est une **double saturation** que la sortie rend vérifiable :\n", + "\n", + "- **Côté demande** : 7 jours × 3 postes × 2 infirmiers (le plancher de couverture) = 42. Chaque créneau du planning affiche exactement 2 infirmiers, jamais 3 — le plancher est serré partout.\n", + "- **Côté offre** : 6 infirmiers × 7 shifts (le plafond de charge) = 42. En comptant les affectations par infirmier dans la sortie, chacun travaille **exactement 7 shifts** — aucun à 6, aucun à 5. Charge totale = capacité totale : le solveur n'a aucune marge.\n", + "\n", + "L'unicité journalière se vérifie de même : chaque jour, chaque infirmier n'apparaît que sur un seul poste. Minimiser le total de shifts sous un plancher de couverture revient ici à *serrer simultanément* les deux bornes — c'est pourquoi `Minimize(total)` trouve 42, et pas un shift de plus.\n", + "\n", + "Note de modélisation : le modèle n'impose **pas** d'équité entre infirmiers au-delà du plafond — l'exercice 3 ci-dessous introduit précisément un plancher individuel (`min_shifts = 6`) et une contrainte de jours consécutifs pour durcir cet aspect." + ] + }, { "cell_type": "markdown", "id": "776131ba", @@ -512,7 +559,7 @@ "| **Performance pure** | État de l'art | Identique (même cœur C++) |\n", "| **Friction d'installation** | Aucune (pip) | Aucune (NuGet, restore automatique) |\n", "\n", - "**Verdict** : les deux bindings **modélisent les mêmes problèmes** (JSSP-3×3, RCPSP-6×2×2, Nurse-6×7×3) avec les mêmes contraintes globales. Les makespans optimaux = **11 / 10 / 42** sont visibles dans les outputs des cellules 6, 8 et 10 ci-dessus, et correspondent exactement aux valeurs du [binôme Python](CSP-4-Scheduling.ipynb) : c'est la parité *native-both* au sens du registre twin-parity (See #10382)." + "**Verdict** : les deux bindings **modélisent les mêmes problèmes** (JSSP-3×3, RCPSP-6×2×2, Nurse-6×7×3) avec les mêmes contraintes globales. Les makespans optimaux = **11 / 10 / 42** sont visibles dans les outputs des sections 1, 2 et 3 ci-dessus, et correspondent exactement aux valeurs du [binôme Python](CSP-4-Scheduling.ipynb) : c'est la parité *native-both* au sens du registre twin-parity (See #10382)." ] }, { From 40e45b4cd3b4fb890209c1c88a99a5fe14ce68d0 Mon Sep 17 00:00:00 2001 From: jsboige Date: Wed, 2 Sep 2026 23:00:32 +0200 Subject: [PATCH 2/2] chore(twin,#8057): rebaseline CSP-4 Scheduling pair - C# density tranche Attestation du blob C# f9f04e74 (enrichissement markdown-only 3 interp, PR #14348). Spot-audit Python : PASS - makespans 11/10/42 convergents (native-both), arc JSSP/RCPSP/Nurse identique, exercices 1-4 presents. Co-Authored-By: Claude-Code --- scripts/notebook_tools/twin_pairs.d/csp-4-scheduling.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/notebook_tools/twin_pairs.d/csp-4-scheduling.yaml b/scripts/notebook_tools/twin_pairs.d/csp-4-scheduling.yaml index 764146c1c9..6f9f1d9685 100644 --- a/scripts/notebook_tools/twin_pairs.d/csp-4-scheduling.yaml +++ b/scripts/notebook_tools/twin_pairs.d/csp-4-scheduling.yaml @@ -30,6 +30,12 @@ csharp_sha: dec6fbb66cf2869576080c746195a5b51b4e806d content_python_sha: 0202e1d5294f250ca750453dd1965f7c144babe93ddb64ea69817cc2e023a622 content_csharp_sha: 54bf49004ff44c749b2b32ca49adb6a94c2998420f4e1f41111489b4b79ae401 + - date: "2026-09-02" + by: myia-po-2023:CoursIA + python_sha: fedaed668e1a585ca09b5ed76f79b51c0f93deec + csharp_sha: 75ec7aa8288229651af4572ccbc6b039420afca3 + content_python_sha: 0202e1d5294f250ca750453dd1965f7c144babe93ddb64ea69817cc2e023a622 + content_csharp_sha: f9f04e74c7510cfad667ae013c3be8221c3f813b0a8cd253db396875d0cd4566 known_differences: - "Socle pedagogique commun : interval scheduling + cumulative constraints + disjunctive (no-overlap) + precedence constraints." - "Meme moteur des deux cotes (OR-Tools CP-SAT, coeur C++) via bindings natifs distincts : pip `ortools` (Python) vs NuGet `Google.OrTools` (C#/.NET). Differences d'idiomes documentees dans la table de comparaison du notebook : AddCumulative liste (PY) vs builder fluent .AddDemands (CS), sum() natif vs LinearExpr.Sum."