Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@
"Console.WriteLine($\"Mines a trouver : {board0.RemainingMines}\");\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La configuration initiale génère un plateau de démineur 8×8 avec 10 mines. Le premier clic révèle 15 cellules, laissant 49 cellules inconnues dont 10 mines à localiser."
]
},
{
"cell_type": "markdown",
"id": "e0fe922a",
Expand Down Expand Up @@ -1654,6 +1661,13 @@
"DrawBoard(board0, \"Plateau complet (mines revelees)\", showMines: true);\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L'imprimé « Etat apres le premier clic (4,4) » montre une zone compacte révélée autour du clic — des 1 et des 2, comptages de mines voisines, tout le reste du plateau restant masqué par des points — et le second bloc « Plateau complet (mines revelees) » expose en '*' les mines qui constituaient la solution de cette grille."
]
},
{
"cell_type": "markdown",
"id": "b3a4aecd",
Expand Down Expand Up @@ -2405,6 +2419,13 @@
"DrawBoard(boardRules, \"Apres solveur par regles\");\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Le solveur par règles effectue 2 itérations et identifie 1 déduction certaine, révélant 15 cellules sûres sur les 54 de la frontière et plaçant 1 drapeau sur les 10 mines, sans pour autant gagner la partie."
]
},
{
"cell_type": "markdown",
"id": "6a354ce4",
Expand Down Expand Up @@ -2597,6 +2618,13 @@
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La frontière CSP contient 19 cellules inconnues avec 11 contraintes, et l'énumération trouve 23 solutions valides sans identifier de cellule forcée (ni sûre ni mine), ce qui nécessite une approche probabiliste ou une déduction plus poussée."
]
},
{
"cell_type": "markdown",
"id": "a1t2ranche2md",
Expand Down Expand Up @@ -2835,6 +2863,13 @@
"Console.WriteLine(\"(La contrainte globale restreint l'espace : le compte de forcées peut augmenter.)\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La tranche OR-Tools confirme le §4 par un autre moteur : sur la même frontière (19 cellules), les tests UNSAT de CP-SAT ne forcent aucune cellule — 0 sûre, 0 mine — en 668,9 ms, « confirmation indépendante par propagation CP-SAT, sans énumérer 2^k ». La Démo 2 ajoute la contrainte globale RemainingMines=9 et rend le même verdict, 0 forcée : la ressource globale ne resserre rien sur ce plateau."
]
},
{
"cell_type": "markdown",
"id": "3d618f42",
Expand Down Expand Up @@ -2956,6 +2991,13 @@
"Console.WriteLine($\"Devinettes faites : {pSolver.Guesses.Count}\");\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La partie probabiliste est gagnée : gagne=True. Le décompte des décisions montre l'économie du mode hybride — rules=31, csp=3, guess=1 : une seule devinette pour toute la partie (Devinettes faites : 1), les décisions CSP ayant pris le relais des règles quand elles s'épuisaient."
]
},
{
"cell_type": "markdown",
"id": "ec8421d6",
Expand Down Expand Up @@ -3266,6 +3308,13 @@
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sur 50 parties (plateau 8x8, 10 mines), la hiérarchie imprimée est nette : règles+aléatoire 32/50 (64 %), règles+CSP+aléatoire 36/50 (72 %), règles+CSP+probabilités 41/50 (82 %) — chaque brique ajoute son palier. Le coût y est visible aussi : 0,3 ms/partie pour la plus simple, 0,5 puis 1,0 ms pour les deux hybrides ; et les décisions cumulées racontent la même histoire — random tombe de 46 à 29 à mesure que csp (134 puis 147) et guess (32) prennent le relais."
]
},
{
"cell_type": "markdown",
"id": "865d5176",
Expand Down Expand Up @@ -3461,4 +3510,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}
72 changes: 67 additions & 5 deletions MyIA.AI.Notebooks/Search/Part2-CSP/CSP-4-Scheduling.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@
"print(\"Toutes les dépendances sont prêtes.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L'installation des dépendances OR-Tools est terminée avec succès, permettant l'exécution des solveurs de contraintes pour les problèmes d'ordonnancement. Cette étape est cruciale car OR-Tools fournit les algorithmes avancés de satisfaction de contraintes qui seront utilisés pour résoudre les différents problèmes de scheduling présentés dans ce notebook, tels que le JSSP, le RCPSP et le Nurse Scheduling. OR-Tools est une bibliothèque open source développée par Google qui offre des solveurs puissants pour la programmation linéaire, la programmation en nombres entiers, et surtout la satisfaction de contraintes, qui est au cœur des problèmes traités dans ce notebook. Ces solveurs permettent de trouver des solutions optimales pour des problèmes combinatoires complexes."
]
},
{
"cell_type": "markdown",
"id": "58a3c464",
Expand Down Expand Up @@ -241,6 +248,13 @@
"print(\"Fonction solve_jssp definie.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La fonction solve_jssp implémente un solveur pour le Job Shop Scheduling Problem en utilisant des variables d'intervalle et la contrainte NoOverlap pour garantir qu'une machine ne traite qu'une tâche à la fois, tout en respectant les contraintes de précédence. Cette approche de modélisation est fondamentale pour les problèmes de scheduling avec ressources, et elle peut être étendue à d'autres types de problèmes similaires. Le Job Shop Scheduling Problem est un problème classique de l'ordonnancement où on cherche à affecter des tâches à des machines tout en respectant l'ordre des opérations pour chaque job et en minimisant le temps total."
]
},
{
"cell_type": "markdown",
"id": "ee9968dc",
Expand Down Expand Up @@ -309,6 +323,13 @@
"print(f\"Status: {result['status']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Deux lignes imprimées, un contrat tenu : « Makespan optimal: 11 » et « Status: OPTIMAL ». L'instance (`jobs_data` ci-dessus) est volontairement minuscule — 3 jobs de 7 unités de travail chacun (J0 : M0-M1-M2 en 3+2+2 ; J1 : M0-M2-M1 en 2+1+4 ; J2 : M1-M2 seul, 4+3) — assez petite pour vérifier à la main, et assez contrainte pour que le makespan 11 soit loin de la somme des durées (21) : précédences et partage des machines font tout l'écart. La charge par machine se lit directement dans `jobs_data` : M0 porte 3+2=5 unités, M1 porte 2+4+4=10, M2 porte 2+1+3=6 — la machine M1, la plus chargée, donne une borne inférieure de 10 ; l'optimum 11 ne la dépasse que d'une unité."
]
},
{
"cell_type": "markdown",
"id": "3b40cec9",
Expand All @@ -331,7 +352,7 @@
"|--------|--------|---------------|\n",
"| Makespan | 11 unités | Temps minimum pour compléter les 3 jobs |\n",
"| Status | OPTIMAL | Solution optimale garantie par CP-SAT |\n",
"| Charge machines | ~92% | Utilisation efficace des ressources |\n",
"| Charge machines | max : M1 = 10/11 ≈ 91 % | La machine la plus chargée porte 10 unités sur le makespan 11 ; charge globale 21/33 ≈ 64 % |\n",
"| Opérations | 8 au total | Toutes ordonnancées sans conflit |\n",
"\n",
"**Points clés** :\n",
Expand All @@ -340,7 +361,7 @@
"3. Les contraintes de précédence dans chaque job sont respectées (ordre séquentiel)\n",
"4. La modélisation avec IntervalVar permet d'exprimer ces contraintes de manière compacte\n",
"\n",
"> **Note technique** : La contrainte NoOverlap est une contrainte globale qui assure qu'un ensemble d'intervalles ne se chevauchent pas. Elle est beaucoup plus efficace que d'écrire toutes les paires de disjonctions manuellement (O(n²) contraintes)."
"> **Note technique** : La contrainte NoOverlap est une contrainte globale qui assure qu'un ensemble d'intervalles ne se chevauchent pas. Elle est beaucoup plus efficace que d'écrire toutes les paires de disjonctions manuellement (O(n²) contraintes).\n"
]
},
{
Expand Down Expand Up @@ -436,7 +457,9 @@
"Cette visualisation permet de vérifier que :\n",
"- Les contraintes de disjonction (NoOverlap) sont respectées\n",
"- Les contraintes de précédence dans chaque job sont respectées\n",
"- Le makespan est correctement identifié\n"
"- Le makespan est correctement identifié\n",
"\n",
"Sur la sortie tracée : chaque couleur est un job, les barres d'une même machine se suivent sans chevauchement, et l'enveloppe totale culmine au makespan optimal de 11 — les trois « colonnes » visibles sont M0, M1 et M2, M1 restant la plus chargée (10 unités sur 11).\n"
]
},
{
Expand Down Expand Up @@ -578,6 +601,13 @@
"print(\"Fonction solve_rcpsp definie.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La fonction solve_rcpsp étend le solveur pour le Resource-Constrained Project Scheduling Problem, en ajoutant la gestion des ressources renouvelables et des contraintes de précédence entre les tâches, ce qui complexifie significativement le problème et nécessite une approche de modélisation plus sophistiquée avec des variables de ressources et des contraintes de capacité. Le RCPSP est une généralisation du JSSP qui prend en compte les contraintes de ressources renouvelables, ce qui le rend plus réaliste mais aussi plus complexe à résoudre."
]
},
{
"cell_type": "markdown",
"id": "a420363f",
Expand Down Expand Up @@ -652,6 +682,13 @@
"print(f\"Status: {rcpsp_result['status']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pour le RCPSP, le solveur obtient un makespan optimal de 10 unités de temps, en respectant toutes les contraintes de précédence et de ressources. Ce résultat optimal est garanti par l'approche CP-SAT qui explore systématiquement l'espace des solutions admissibles pour trouver le meilleur ordonnancement possible, en tenant compte des limitations de ressources. L'exemple RCPSP avec 6 tâches et 2 ressources illustre comment le solveur gère simultanément les contraintes temporelles et les contraintes de capacité."
]
},
{
"cell_type": "markdown",
"id": "59c7b658",
Expand Down Expand Up @@ -777,7 +814,9 @@
"- **Flèches rouges** : dépendances entre tâches (précédences)\n",
"- **Couleurs graduées** : distinction visuelle des tâches\n",
"\n",
"Cette visualisation permet de vérifier que les contraintes de précédence et de capacité sont respectées, et d'identifier le chemin critique qui détermine le makespan.\n"
"Cette visualisation permet de vérifier que les contraintes de précédence et de capacité sont respectées, et d'identifier le chemin critique qui détermine le makespan.\n",
"\n",
"Sur la sortie tracée : les flèches matérialisent les précédences posées dans `tasks`, et l'enveloppe des barres s'étend exactement au makespan optimal de 10 — raccourcir une tâche critique allongerait le chemin, le resource-cap l'empêche.\n"
]
},
{
Expand Down Expand Up @@ -920,6 +959,13 @@
"print(\"Fonction solve_nurse_scheduling definie.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"La signature dit tout du modèle : `solve_nurse_scheduling(num_nurses, num_days, shifts_per_day, min_nurses_per_shift, max_shifts_per_nurse)`. Deux familles de contraintes, rien de plus — la couverture minimale par poste, et le plafond de charge par infirmier. Les variables sont booléennes, une par triplet x[nurse, day, shift], construites dans la boucle triple du modèle. Pas de préférences individuelles ni de compétences dans ce modèle-jouet : toute la difficulté tient dans le mariage couverture × plafond. La contrainte de couverture impose au moins min_nurses_per_shift infirmiers sur chaque poste de chaque jour ; la seconde plafonne le total par infirmier à max_shifts_per_nurse sur l'horizon entier — c'est ce second plafond qui empêche de concentrer les 42 postes sur trop peu d'infirmiers."
]
},
{
"cell_type": "markdown",
"id": "798b3681",
Expand Down Expand Up @@ -994,6 +1040,13 @@
"print(f\"Assignations: {len(nurse_result['schedule'])}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Trois lignes imprimées : « Status: OPTIMAL », « Total shifts: 42 », « Assignations: 42 ». Les 42 postes (2 infirmiers minimum × 7 jours × 3 postes, note du code) sont couverts un à un — 42 affectations pour 42 postes — par une solution que le statut OPTIMAL garantit optimale pour le modèle, c'est-à-dire respectant à la fois la couverture minimale et le plafond max_shifts_per_nurse. Six infirmiers couvrent ces 42 postes (le bilan du notebook parle d'« un planning valide pour 6 infirmiers sur 7 jours »), soit 7 postes en moyenne par infirmier."
]
},
{
"cell_type": "markdown",
"id": "cd08ca4c",
Expand Down Expand Up @@ -1133,7 +1186,9 @@
"- **Respect** des contraintes de couverture minimale\n",
"- **Continuité** du service (aucun poste non couvert)\n",
"\n",
"Le diagramme montre chaque infirmier en ligne du temps, avec les postes colorés selon le moment de la journée.\n"
"Le diagramme montre chaque infirmier en ligne du temps, avec les postes colorés selon le moment de la journée.\n",
"\n",
"Sur la sortie tracée : chaque ligne est une infirmière, chaque colonne un poste, et le tableau permet de compter les 42 postes couverts par les 6 infirmiers — soit 7 postes moyens chacun, la couverture minimale de 2 par poste étant satisfaite partout.\n"
]
},
{
Expand Down Expand Up @@ -1257,6 +1312,13 @@
"print(f\"Gap: {(spt_result['makespan'] - cp_result['makespan']) / cp_result['makespan'] * 100:.1f}%\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Trois lignes, un verdict : « CP-SAT optimal: 11 », « SPT heuristic: 18 », « Gap: 63.6% ». Sur cette instance unique (le JSSP 3×3 de la section 1), l'heuristique SPT — priorité à l'opération la plus courte — laisse 7 unités sur la table, soit 64 % de makespan en plus ((18−11)/11). L'écart mesure le coût de la myopie locale de SPT sur CETTE instance ; il n'est pas extrapolable aux grandes instances, où l'écart des dispatching rules varie — mais il illustre pourquoi CP-SAT reste la référence quand l'optimalité compte. Le tableau de la section 4 classe les trois problèmes par variables et contraintes ; ce benchmark lui ajoute la dimension solveur — même instance, deux méthodes, écart chiffré."
]
},
{
"cell_type": "markdown",
"id": "221d643d",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
date: '2026-09-22'
by: myia-po-2025:CoursIA
python_sha: c02276a7415fbf7167db80c7150027e463f815ce
csharp_sha: 126266ed3ebcaf959576b584e465cdd1c2790f23
content_python_sha: 77e45adc097afd2dee3486b30d1f81850f26458f8169d785e66b1a9be7de0b3d
content_csharp_sha: 599fe73edd83acaa177e887aa47fefe625dc2358db288f8b41d69111bc2c3516
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
date: '2026-09-22'
by: myia-po-2025:CoursIA
python_sha: 4c02581f0dc5d9d7b8ee1092c03517f5457c5517
csharp_sha: 75ec7aa8288229651af4572ccbc6b039420afca3
content_python_sha: 0d3d9df94d5ad875d72f216d3949e4f01c0310b87f152cdb43851c85404e402a
content_csharp_sha: f9f04e74c7510cfad667ae013c3be8221c3f813b0a8cd253db396875d0cd4566
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
date: '2026-09-22'
by: myia-po-2025:CoursIA
python_sha: d83efc4016883804b61c4b6b8f58c8f066e5b2a3
csharp_sha: 75ec7aa8288229651af4572ccbc6b039420afca3
content_python_sha: 311873742f16fb474666d97d9b604fafa0c3ee05656a3ff0b5be2ce4c53b9735
content_csharp_sha: f9f04e74c7510cfad667ae013c3be8221c3f813b0a8cd253db396875d0cd4566
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
date: '2026-09-22'
by: myia-po-2025:CoursIA
python_sha: 8e4acea56198f367d4b508d2b901a030b2b16140
csharp_sha: 75ec7aa8288229651af4572ccbc6b039420afca3
content_python_sha: c6c6dc1fd18ba43fa243339b9a13efb2f8955956205ecb1e743c5d69362acbb7
content_csharp_sha: f9f04e74c7510cfad667ae013c3be8221c3f813b0a8cd253db396875d0cd4566
Loading