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
147 changes: 147 additions & 0 deletions MyIA.AI.Notebooks/Search/Part2-CSP/CSP-1-Fundamentals.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,23 @@
" print(f\" {v:>3} -> {n}\")"
]
},
{
"cell_type": "markdown",
"id": "c107csp1-adjacences-comptage",
"metadata": {},
"source": [
"### Lecture du comptage : 9 contraintes reconstruites depuis les adjacences\n",
"\n",
"La sortie imprime chaque région avec sa liste de voisins. En additionnant les longueurs des sept listes ci-dessus — 2 pour WA, 3 pour NT, 5 pour SA, 3 pour Q, 3 pour NSW, 2 pour V, 0 pour T — on obtient 18 entrées orientées. Chaque paire de régions voisines apparaît deux fois dans ces listes (WA cite NT, NT cite WA) : la division 18 / 2 = 9 redonne exactement le total affiché par la ligne `Contraintes : 9 paires`. Le compte annoncé est donc aussi un compte reconstruisible à la main depuis la structure imprimée.\n",
"\n",
"Deux observations structurelles sur cette même sortie :\n",
"\n",
"1. SA porte 5 des 9 contraintes (5/9, soit 56 %) : c'est le noeud pivot du graphe, celui que l'heuristique MRV de la section 5 ciblera dès que ses voisins seront coloriés.\n",
"2. T ferme la sortie avec `T -> []` : zéro voisin, zéro contrainte, couleur totalement libre. Cette liberté aura une conséquence mesurable sur le compte de solutions de la section 6 (énumération exhaustive).\n",
"\n",
"Enfin l'espace brut affiché, `2187`, se vérifie comme 3^7 : sept variables, trois couleurs chacune, aucune contrainte encore appliquée. C'est la borne supérieure de ce que la brute force de la section 4 devra balayer pour n'en retenir que 18 solutions.\n"
]
},
{
"cell_type": "markdown",
"id": "aa57c0af",
Expand Down Expand Up @@ -981,6 +998,20 @@
"- L'indentation montre la profondeur de recursion"
]
},
{
"cell_type": "markdown",
"id": "c121csp1-trace-zero-backtrack",
"metadata": {},
"source": [
"### Lecture de la trace : sept essais, zéro retour arrière\n",
"\n",
"Le comptage ligne à ligne de la trace donne : sept essais de valeur au total, dont quatre marqués `(consistant)` et trois marqués `(CONFLIT)` — l'égalité 4 + 3 = 7 correspond au compteur final `Assignations tentees : 7`. Les quatre essais consistants sont exactement les quatre variables du problème (A, B, C, D, une fois chacune) : aucune valeur validée n'a jamais été remise en cause.\n",
"\n",
"Le détail le plus instructif : la chaîne `-> backtrack` n'apparaît nulle part dans la sortie. Les trois conflits (B = R, puis C = R et C = V) ont tous été résolus en passant à la valeur suivante de la même variable, jamais en désassignant une variable parente. L'indentation le confirme visuellement : elle progresse de quatre niveaux sans jamais reculer, donc le chemin parcouru n'a subi aucun retour.\n",
"\n",
"Cette instance est un cas d'école « sans retour arrière » : 7 essais contre 3^4 = 81 combinaisons pour une brute force, soit environ 9 % de l'espace réellement visité. Ce régime favorable n'a rien de général — la même stratégie naïve accumulera 876 essais et de nombreux retours sur les 8-Reines (section 5), ce qui motivera les heuristiques MRV et LCV.\n"
]
},
{
"cell_type": "markdown",
"id": "l07u2toghu",
Expand Down Expand Up @@ -1249,6 +1280,20 @@
"viz.draw(max_depth=4, title=\"Arbre de Backtracking - Coloration Australie\")"
]
},
{
"cell_type": "markdown",
"id": "c126csp1-noeuds-trajectoire",
"metadata": {},
"source": [
"### Lecture du compte de noeuds : deux implémentations, même trajectoire\n",
"\n",
"La sortie chiffre l'arbre : `Nombre de noeuds explores : 11` et `Nombre de valeurs rejetees : 4`. La différence 11 - 4 = 7 redonne exactement les sept variables du problème : chaque noeud est soit une assignation retenue (7), soit une valeur rejetée à la volée (4). Chaque rejet correspond à un conflit détecté par `consistent()` avant toute récursion — ce sont des branches coupées à la naissance, jamais explorées.\n",
"\n",
"Le rapprochement le plus instructif est cross-cellule : le backtracking simple de la section 4 affichait lui aussi 11 assignations, et sa solution était `{'WA': 'Rouge', 'NT': 'Vert', 'SA': 'Bleu', ...}`. En renommant R en Rouge, G en Vert et B en Bleu, la solution imprimée ici (`{'WA': 'R', 'NT': 'G', 'SA': 'B', ...}`) est la coloration identique. Deux implémentations indépendantes — avec et sans instrumentation visuelle — parcourent la même trajectoire parce qu'elles partagent le même ordre naïf des variables et des valeurs : l'instrumentation n'a pas perturbé la recherche, ce qui valide la visualisation comme fidèle au calcul.\n",
"\n",
"Remarque d'échelle : le dessin est limité à `max_depth=4` pour la lisibilité, mais les compteurs (11 noeuds, 4 rejets) couvrent la recherche complète, pas seulement la portion dessinée.\n"
]
},
{
"cell_type": "markdown",
"id": "tgyto74w32o",
Expand Down Expand Up @@ -1925,6 +1970,20 @@
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "c143csp1-cles-mrv",
"metadata": {},
"source": [
"### Lecture de l'ordre des clés : MRV rendu visible par le dictionnaire\n",
"\n",
"Le détail révélateur de cette sortie est l'ordre des clés imprimé : `{0: 0, 1: 4, 2: 7, 3: 5, 6: 1, 4: 2, 5: 6, 7: 3}`. La colonne 6 apparaît en cinquième position, avant les colonnes 4 et 5. Un ordre d'assignation naïf aurait produit 0, 1, 2, 3, 4, 5, 6, 7 : l'écart témoigne que la sélection des variables a été réordonnée en cours de recherche — c'est MRV, qui a traité la colonne 6 plus tôt parce que son domaine viable était plus restreint à cet instant. L'ordre d'insertion d'un dict Python mémorise l'ordre des assignations : il rend l'heuristique observable sans instrumenter le code.\n",
"\n",
"Deux vérifications arithmétiques sur les valeurs : les huit lignes {0, 4, 7, 5, 1, 2, 6, 3} sont exactement les entiers de 0 à 7, tous distincts — une reine par ligne, par construction du modèle (une variable par colonne) — et la ligne de vérification conclut `VALIDE`, diagonales incluses.\n",
"\n",
"Mise en perspective : 677 assignations face à l'espace brut 8^8 = 16 777 216, soit environ 4 dix-millièmes de l'espace visité (un facteur de réduction d'environ 24 800). Le temps `3.37 ms` est une mesure machine-dépendante sur un seul passage, non moyennée : c'est le compte d'assignations, structurel, qui fait foi.\n"
]
},
{
"cell_type": "markdown",
"id": "39daf9c3",
Expand Down Expand Up @@ -2331,6 +2390,20 @@
"3. L'API déclarative est plus lisible et moins sujette aux erreurs"
]
},
{
"cell_type": "markdown",
"id": "c152csp1-parite-18",
"metadata": {},
"source": [
"### Lecture croisée : premières solutions différentes, compte identique\n",
"\n",
"La solution renvoyée ici commence par `{'SA': 'Bleu', 'NSW': 'Vert', 'Q': 'Rouge', ...}` — un ordre de clés et une coloration qui diffèrent du backtracking manuel (WA en premier, T = Rouge) : la bibliothèque attribue ici T = Bleu. Aucune incohérence : chaque solveur visite l'espace dans son propre ordre, et la première solution rencontrée dépend de cet ordre. Sur un problème à solutions multiples, comparer des premiers résultats n'a de sens qu'à parcours fixe ; seuls les comptes exhaustifs sont comparables.\n",
"\n",
"La grandeur qui doit coïncider coïncide : `Nombre total de solutions : 18`, exactement les 18 solutions comptées par la brute force en section 4. Deux moteurs indépendants, un même espace de solutions — la vérification croisée la plus forte disponible sur ce problème.\n",
"\n",
"Côté coûts, honnêtement : les temps imprimés (`0.11 ms` pour la première solution, `0.26 ms` pour les 18) sont machine-dépendants et non moyennés. Surtout, le solveur interne de la bibliothèque n'est pas instrumenté ici : contrairement à notre classe CSP, aucun compteur d'assignations n'est exposé. On ne sait donc pas combien d'essais internes coûtent ces 0,26 ms — la comparaison avec le backtracking manuel (11 assignations chiffrées) reste asymétrique.\n"
]
},
{
"cell_type": "markdown",
"id": "d0218284",
Expand Down Expand Up @@ -2400,6 +2473,22 @@
" print(f\" {s}\")"
]
},
{
"cell_type": "markdown",
"id": "c155csp1-alldifferent-256-24",
"metadata": {},
"source": [
"### Lecture : une contrainte globale fait passer l'espace de 256 à 24\n",
"\n",
"La sortie affiche `Nombre de solutions : 24 (= 4! = 24)` et la vérification est immédiate : quatre variables sur un domaine de quatre valeurs, toutes différentes — chaque solution est une permutation de {1, 2, 3, 4}, et il y en a exactement 4 x 3 x 2 x 1 = 24.\n",
"\n",
"La réduction se quantifie par rapport à l'espace non contraint : sans AllDifferent, l'espace brut serait 4^4 = 256. Une seule contrainte globale suffit à le diviser par 256 / 24, soit environ 10,7 — et ce, avant toute recherche : c'est de la propagation déclarative, pas de l'élagage pendant le parcours. C'est tout l'intérêt des contraintes globales face à la décomposition en contraintes binaires équivalentes : le solveur raisonne sur la structure entière du groupe.\n",
"\n",
"Les trois solutions échantillonnées en fin de sortie se vérifient au vol : `{'A': 4, 'B': 3, 'C': 2, 'D': 1}`, `{'A': 4, 'B': 3, 'C': 1, 'D': 2}`, `{'A': 4, 'B': 2, 'C': 3, 'D': 1}` — chacune contient les quatre valeurs exactement une fois. Leur ordre (A = 4 en tête partout, puis B décroissant) révèle l'énumération lexicographique descendante du solveur : utile pour prévoir quelle solution un `getSolution()` renverra en premier.\n",
"\n",
"Cette brique est celle qui porte la dureté des modèles réels — le Sudoku en est l'illustration canonique.\n"
]
},
{
"cell_type": "markdown",
"id": "072d8c38",
Expand Down Expand Up @@ -2526,6 +2615,20 @@
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "c157csp1-miroir-4reines",
"metadata": {},
"source": [
"### Lecture : les deux solutions sont miroirs, vérifiable en une ligne\n",
"\n",
"La sortie liste exactement deux placements : `Solution 1 : lignes = [2, 0, 3, 1]` et `Solution 2 : lignes = [1, 3, 0, 2]`. La relation entre les deux se vérifie terme à terme : 3 - 2 = 1, 3 - 0 = 3, 3 - 3 = 0, 3 - 1 = 2. La seconde solution est l'image miroir verticale de la première — chaque reine garde sa colonne et passe à la ligne symétrique par rapport à l'axe horizontal de l'échiquier. Propriété remarquable de cette paire : la lecture inversée de la première liste, [1, 3, 0, 2], redonne aussi la seconde — sur cette instance, la réflexion des colonnes produit le même résultat que la réflexion des lignes.\n",
"\n",
"Pourquoi seulement deux ? L'espace brut est 4^4 = 256 placements ; les contraintes de ligne et de diagonale, imposées paire à paire dans le modèle, ne laissent que ces deux placements valides. Les damiers imprimés le confirment visuellement : aucune paire de reines ne partage une ligne, une colonne ou une diagonale.\n",
"\n",
"Généralisation sûre : le miroir d'une solution est toujours une solution (les contraintes sont invariantes par réflexion), donc les solutions vont par paires miroirs — un comptage impair serait suspect a posteriori. Le temps `0.16 ms` est machine-dépendant, un seul passage ; la grandeur structurelle est le compte : 2.\n"
]
},
{
"cell_type": "markdown",
"id": "feb7518b",
Expand Down Expand Up @@ -2689,6 +2792,20 @@
"**Sortie obtenue** : Choco trouve une coloration valide par propagation de contraintes (pas d'enumeration aveugle). Le temps en ms affiche est une mesure *machine-dep* en sortie live de la cellule ci-dessus -- regle #9434, non fige en prose. On peut le comparer au temps d'enumeration de la cellule brute-force de la section 4 : la propagation evite d'explorer les 2187 combinaisons.\n"
]
},
{
"cell_type": "markdown",
"id": "c162csp1-meme-coloriage",
"metadata": {},
"source": [
"### Lecture : le même coloriage que le backtracking naïf, par un chemin différent\n",
"\n",
"La sortie imprime chaque région avec sa valeur interne et son nom : `WA = Rouge (0)`, `NT = Vert (1)`, `SA = Bleu (2)`, etc. Ces annotations révèlent l'encodage du modèle Choco — des IntVar sur {0, 1, 2} — le mapping vers les noms de couleurs n'étant qu'une couche d'affichage ajoutée pour la lisibilité.\n",
"\n",
"Le fait saillant est cross-cellule : cette coloration est exactement celle du backtracking manuel de la section 4 (WA Rouge, NT Vert, SA Bleu, Q Rouge, NSW Vert, V Rouge, T Rouge). Or les deux moteurs n'ont rien de commun ici : notre backtracking explore dans l'ordre naïf des variables avec vérification d'assignation au coup par coup, Choco résout par propagation de contraintes sur les domaines. Deux mécanismes différents qui convergent sur la même première solution. Sur une instance petite et fortement contrainte cette convergence est plausible mais n'est pas une garantie : le solveur python-constraint, lui, avait renvoyé une première solution différente (T = Bleu). L'ordre de parcours reste spécifique à chaque moteur.\n",
"\n",
"Vérifications locales sur le résultat imprimé : WA (Rouge) et NT (Vert), adjacents, diffèrent ; SA (Bleu) diffère de ses cinq voisins affichés (WA Rouge, NT Vert, Q Rouge, NSW Vert, V Rouge). Le temps `0.23 ms` est machine-dépendant, un seul passage.\n"
]
},
{
"cell_type": "markdown",
"id": "1aa70242",
Expand Down Expand Up @@ -2766,6 +2883,22 @@
"**Sortie obtenue** : **18 solutions** au total -- exactement le compte de la brute force de la section 4 **et** celui du jumeau C# avec Choco via IKVM. Les trois moteurs (enumeration manuelle, Choco/IKVM cote .NET, Choco/pychoco cote Python) enumerent le meme espace de solutions : la parite lib-vs-lib est verifiee sur une grandeur observable, pas seulement sur l'API.\n"
]
},
{
"cell_type": "markdown",
"id": "c165csp1-decomposition-18",
"metadata": {},
"source": [
"### Lecture : décomposer les 18 solutions en 6 coloriages continentaux x 3\n",
"\n",
"Les cinq solutions imprimées ont une structure frappante. Les solutions 1, 2 et 3 ne diffèrent que par la dernière valeur : WA=Rouge, NT=Vert, SA=Bleu, Q=Rouge, NSW=Vert, V=Rouge à l'identique, avec T qui vaut successivement Rouge, Vert puis Bleu. Les solutions 4 et 5 enchaînent sur un deuxième coloriage continental (NT=Bleu, SA=Vert, NSW=Bleu), toujours avec T libre.\n",
"\n",
"C'est la traduction directe de l'adjacence `T -> []` relevée en section 3 : la Tasmanie, sans aucun voisin, multiplie par 3 le compte de solutions sans toucher au problème continental. D'où la décomposition arithmétique : 18 solutions totales = 6 coloriages du continent x 3 couleurs libres pour T, et 6 x 3 = 18 est conforme au total imprimé `Nombre total de solutions : 18`.\n",
"\n",
"Honnêtement, ce qui n'est pas démontré ici : l'existence d'exactement 6 coloriages continentaux. Les cinq solutions échantillonnées n'en couvrent que 2 ; les quatre autres sont inférées du total (18 / 3), pas affichées. L'égalité 18 = 6 x 3 est une cohérence arithmétique, pas une énumération complète du continent — la vérifier pleinement exigerait d'énumérer les 18 et de dédupliquer selon T, ce que la sortie ne fait pas.\n",
"\n",
"Troisième moteur, même total : ce 18 égale celui de la brute force (section 4) et celui de python-constraint (section 6) — la parité tient sur le compte exact.\n"
]
},
{
"cell_type": "markdown",
"id": "befa500c",
Expand Down Expand Up @@ -2844,6 +2977,20 @@
" print(\"Pas de solution trouvee.\")\n"
]
},
{
"cell_type": "markdown",
"id": "c168csp1-echiquier-verification",
"metadata": {},
"source": [
"### Lecture : vérifier l'échiquier ASCII à partir du mapping imprimé\n",
"\n",
"La sortie donne d'abord le mapping colonne -> ligne : `0->4, 1->6, 2->1, 3->5, 4->2, 5->0, 6->7, 7->3`. Les huit valeurs {4, 6, 1, 5, 2, 0, 7, 3} sont exactement les entiers de 0 à 7 sans doublon : une reine par colonne et une par ligne, condition portée par la contrainte globale `all_different` du modèle.\n",
"\n",
"L'échiquier ASCII se relit avec ce mapping : la ligne `Ligne 7` porte son Q en colonne 6 (conforme à 6->7), la ligne 6 en colonne 1 (1->6), la ligne 5 en colonne 3 (3->5), et ainsi de suite jusqu'à la ligne 0 en colonne 5 (5->0). Grille et mapping sont cohérents ligne à ligne — huit Q au total, un par ligne affichée.\n",
"\n",
"Pour les diagonales, trois couples vérifiés à la main sur le mapping : colonnes 0 et 4 (écart de colonnes 4, écart de lignes |4 - 2| = 2), colonnes 1 et 5 (4 contre |6 - 0| = 6), colonnes 3 et 7 (4 contre |5 - 3| = 2) — aucune paire en prise. Point d'honnêteté : cette cellule n'imprime pas de ligne `VALIDE`, contrairement aux cellules du backtracking manuel qui appelaient `is_solution()`. La validité complète exigerait les 28 paires de colonnes ; les trois sondages ci-dessus ne constituent pas une preuve — celle-ci repose sur la correction de la construction du modèle (all_different + contraintes diagonales scalaires). Le temps `1.41 ms` reste machine-dépendant, un seul passage.\n"
]
},
{
"cell_type": "markdown",
"id": "ca6c8261",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
date: '2026-09-18'
by: myia-po-2026:CoursIA
python_sha: a05289b35076b538ab170a0872ef3919858949ad
csharp_sha: 166123a43b29965a0bbef11f074d9f21d38c0c2b
content_python_sha: 2af16bbbd3fa0aa4c754a2591ef85cf746cbeac349894fefea700d0b3d77a95a
content_csharp_sha: c84bc9e73110d0ac0bc627f67b9cfa3f3521b477da0c40a2f8d4d97a6d58c222
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
date: '2026-09-19'
by: myia-po-2026:CoursIA
python_sha: d6ddfde77a392617afc0838d94be5ed1a09ed065
csharp_sha: 166123a43b29965a0bbef11f074d9f21d38c0c2b
content_python_sha: b9567213cca43aa36cb47feeeb52733dd1488ebaa6262a1dbc589b5c7cc80fd5
content_csharp_sha: c84bc9e73110d0ac0bc627f67b9cfa3f3521b477da0c40a2f8d4d97a6d58c222
Loading