Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion MyIA.AI.Notebooks/Search/Part2-CSP/CSP-4-Scheduling-Csharp.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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)."
]
},
{
Expand Down
6 changes: 6 additions & 0 deletions scripts/notebook_tools/twin_pairs.d/csp-4-scheduling.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
Loading