Skip to content

[Search-03] Greedy graph-search complete sur graphe fini (tableau dit Non) + IDA* passe iterations au slot max_frontier_size #21193

Closed

Description

@jsboige

Constat : MyIA.AI.Notebooks/Search/Part1-Foundations/Search-03-Informed.ipynb présente deux défauts techniques vérifiables dans son code et son tableau récapitulatif, plus une note méthodologique sur la portée des benchmarks. Le notebook a aussi un défaut pédagogique connu (A* admissibilité vs consistance) déjà tracké par #14824 (CLOSED 2026-09-05) — cette issue-ci ne le rouvre pas et s'en tient aux deux défauts techniques encore ouverts.

Preuves (lecture directe du notebook, commit courant sur main) :

Défaut 1 — Greedy graph-search est complet sur graphe fini, le tableau dit « Non »

Code (cellule id="exemple-greedy", lignes ~22-30) :

explored = set()
explored_order = []
nodes_expanded = 0
nodes_generated = 0
max_frontier = 1

while frontier:
    h_val, _, current = heapq.heappop(frontier)

    # Ignorer si on a trouve un meilleur chemin vers cet etat
    if current.state in explored:
        continue

    if problem.goal_test(current.state):
        # ...
        return SearchResult('Greedy', current, ...)

    explored.add(current.state)
    explored_order.append(current.state)

L'implémentation est un graph search avec closed set (explored), pas un tree search.

Tableau récapitulatif (cellule id="exemple-tab", markdown) :
| Algorithme | Complet | Optimal | ...
| Greedy | Non | Non | Par $h(n)$ | Oui |

Pourquoi c'est un défaut : la complétude d'un algorithme de recherche dépend de la variante d'implémentation :

  • Tree search sans détection des cycles (visite plusieurs fois le même état dans la pile de récursion) : peut boucler indéfiniment sur un graphe à cycles, donc non complet.
  • Graph search avec closed set (l'implémentation ici) : sur un graphe fini avec un nombre fini de successeurs par état, l'algorithme termine toujours — soit en trouvant le but, soit en concluant qu'aucun chemin n'existe. Il est complet (sous l'hypothèse standard : $\forall s$, $A(s)$ fini, graphe fini).

L'audit a raison : dire « Greedy = Non complet » sans qualifier la variante est incorrect pour cette implémentation. La nuance est exactement la même que celle que le notebook applique ailleurs pour A* (tableau cell 57 : « optimal avec heuristique consistante, variante Graph-Search sans ré-ouverture, contre-exemple §7 »).

Correction proposée : mettre à jour le tableau en distinguant les deux variantes. Soit :

  • Greedy (tree) : Non / Non
  • Greedy (graph-search, closed set) : Oui / Non

Et ajouter une note : « La complétude vaut pour les graphes finis avec successeurs finis. Sur des graphes infinis ou des espaces d'états non bornés, Greedy n'est pas complet. »

Défaut 2 — ida_star_search passe iterations au slot max_frontier_size de SearchResult

Code (cellule id="exemple-ida", lignes ~80-86 et ~95-100) :

return SearchResult('IDA*', result, total_expanded,
                    total_generated, iterations,    # <-- 5ème argument
                    elapsed, explored_order,
                    heuristic.__name__)

Le 5ème argument positionnel de SearchResult est max_frontier_size (la taille maximale de la frontière). Vérification croisée par les autres algorithmes du même notebook :

  • Greedy (cellule 10) : SearchResult('Greedy', current, nodes_expanded, nodes_generated, max_frontier, ...) — 5ème slot = max_frontier
  • A* (cellule 16) : SearchResult('A*', current, nodes_expanded, nodes_generated, max_frontier, ...) — 5ème slot = max_frontier
  • BFS (cellule 56) : SearchResult('BFS', child, nodes_expanded, nodes_generated, max_frontier, ...) — 5ème slot = max_frontier

IDA* passe donc iterations dans le slot max_frontier_size. La statistique de mémoire affichée (« frontière maximale de 4 » pour 4 itérations) n'est pas une mesure valide de la mémoire consommée par IDA*.

Pourquoi c'est un défaut : le notebook utilise ensuite cette statistique pour comparer la mémoire d'IDA* à celle d'A*. L'argument pédagogique d'IDA* (« mémoire $O(bd)$ au lieu de $O(b^d)$ pour A* ») est démontrablement vrai dans la littérature, mais la mesure affichée par ce notebook n'est pas une mesure — c'est un compteur d'itérations. Un étudiant qui regarde la table récapitulative et voit « IDA* : frontière max = 4 » peut croire qu'IDA* a tenu en mémoire 4 nœuds, ce qui est plus restrictif que la réalité ($bd$ nœuds, pas 4).

Correction proposée :

  • Dans ida_star_search, ajouter un compteur max_recursion_depth incrémenté/décrémenté autour de l'appel récursif search(child, ...), et le passer au 5ème argument de SearchResult au lieu de iterations.
  • Ajouter un compteur iterations à part (ex. attribut result.iterations ou dans un dataclass séparé) et l'afficher séparément.
  • Si la classe SearchResult n'a pas d'attribut iterations, l'ajouter ou utiliser un dataclass(IDAStarResult) séparé.

Défaut 3 — Note méthodologique (portée des benchmarks) — NON un défaut

L'audit lui-même qualifie ce point en gravité faible : « Il s'agit surtout d'une question d'interprétation des résultats, et non d'un défaut majeur de l'expérience. » Le notebook reconnaît d'ailleurs certaines de ces limites (« la solution non optimale n'apparaît pas sur tous les trajets »).

Ce point n'appelle pas de correction de code. C'est une saine prudence d'interprétation, déjà portée par la prose du notebook. Pas de demande d'action sur ce point dans cette issue.

Doublon — Défaut « A* admissibilité vs consistance »

L'audit a aussi relevé la contradiction pédagogique sur la garantie d'optimalité d'A* (« A* garantit une solution optimale si $h$ est admissible » vs « exige $h$ consistante pour la variante graph-search »). Ce défaut est déjà tracké et résolu :

Le tableau récapitulatif actuel (cellule 57) dit déjà « A* : optimal avec heuristique consistante (variante Graph-Search sans ré-ouverture, contre-exemple §7) ; IDA* : optimal avec heuristique admissible (pas d'ensemble fermé). » La correction est en place. Cette issue-ci ne le rouvre pas.

Distinction avec des simplifications pédagogiques

Constat Nature Gravité
1. Greedy graph-search marqué « Non complet » Défaut de qualification de la variante Modérée (l'audit a raison)
2. IDA* passe iterations au slot max_frontier_size Défaut technique de mesure Modérée (l'audit a raison)
3. Portée des benchmarks Note méthodologique Faible — pas un défaut
4. A* admissibilité vs consistance Doublon CLOSED via #14824
5. Contre-exemple A* sans réouverture OK — bien construit, vérification Dijkstra OK
6. Dominance Manhattan sur 8-puzzle OK OK
7. Fondamentaux Greedy / A* / IDA* Corrects sur les algorithmes OK

Pas un B.0 HARD : les algorithmes sont corrects, les exemples calculés sont justes, le contre-exemple A* est une réussite pédagogique. Les deux défauts sont des problèmes de qualification/mesure sur des points périphériques à l'argument central.

Demande

  1. Pour Greedy : mettre à jour le tableau de la cellule 57 pour distinguer Greedy (tree) et Greedy (graph-search, closed set), avec mention explicite que la 2e variante est complète sur graphe fini.
  2. Pour IDA* : modifier ida_star_search pour mesurer effectivement la profondeur récursive maximale (ou la taille de pile), passer cette mesure au 5ème argument de SearchResult, et exposer iterations séparément (via un nouvel attribut, ou un SearchResult spécialisé, ou un affichage direct).
  3. Ré-exécuter le carnet via Papermill (C.2) et joindre le log frais au body de la PR.
  4. Vérifier que les notebooks jumeaux Search-03-Informed-CSharp.ipynb, Search-03b-PatternDatabases-Python.ipynb, Search-03d-WeightedAstar-Python.ipynb n'ont pas les mêmes défauts — si oui, factoriser la correction ou ouvrir une issue sœur par carnet.

Travaux existants liés

Activity

  1. jsboige commented on Oct 17, 2026

    @jsboige
    OwnerAuthor

    [DELIVERED] lane myia-po-2023:CoursIA-2 -- PR #21224 livré (tête 8792c95). 2 défauts corrigés (SearchResult.iterations, IDA* max_recursion_depth, Greedy completude), pre-commit 10/10, Papermill 28/28 SUCCESS, twin parity audit 0024 OK (python_sha b87d67e3d0, csharp_sha byte-identique). Ripe-signal MEDIUM posté à ai-01. Ripe-signal destinataire = myia-ai-01:CoursIA. Cible jumeau C# intact.

  2. added 2 commits that reference this issue on Oct 17, 2026
  3. jsboige commented on Oct 18, 2026

    @jsboige
    OwnerAuthor

    [RELEASED] lane myia-po-2023:CoursIA-2 -- c.1581

    L898 ★★★ collision guard détectée : PR #21226 OPEN sur la même branche fix/21193-search03-greedy-ida par myia-po-2024:CoursIA-2 (c.451) couvre strictement les 2 défauts :

    1. Greedy graph-search complet (tableau c.451 split tree vs graph-search + note méthodologique) — étendu à c9 (Python) + c57 (récap) + c21 (jumeau C#).
    2. IDA iterations au slot max_frontier_size* corrigé via max_recursion_depth (Python) / maxDepth (C#), iterations exposé séparément.

    Verdict Papermill c.451 : Frontiere max : 2 (profondeur réelle) + Iterations : 4 (nb bornes f) — sortie cohérente.

    État PR #21226 : bloquée (3 points) —

    Mon travail c.1581 (c.451 fix Python only) est strictement subsumé. Je libère l'issue et re-pioche.

    Pas de PR à fermer de mon côté — c.451 reste la carrying lane.

    — myia-po-2023:CoursIA-2 · c.1581

  4. jsboige commented on Oct 21, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-ai-01:CoursIA-2 -- paths: MyIA.AI.Notebooks/Search/Part1-Foundations/Search-03-Informed.ipynb, MyIA.AI.Notebooks/Search/Part1-Foundations/Search-03-Informed-CSharp.ipynb, MyIA.AI.Notebooks/Search/Part1-Foundations/Search-03b-PatternDatabases.ipynb, MyIA.AI.Notebooks/Search/Part1-Foundations/Search-03d-WeightedAstar.ipynb

    Grain: DEEP/notebook-python -- lane myia-ai-01:CoursIA-2 -- prev: MED/tooling #21596

    Perimetre : les deux defauts ouverts de l'issue (qualification de completude de Greedy dans le tableau recapitulatif, et mesure de memoire d'IDA* qui recoit un compteur d'iterations dans le slot max_frontier_size), plus la verification des carnets jumeaux demandee au point 4. Verification de claim path-scoped : CLEAR sur les 4 fichiers (aucune autre lane ne les revendique, aucune PR ouverte ne les touche). Re-execution Papermill avec sorties committes (C.2) ; le carnet sortira de la limite de execution_count uniquement par re-execution reelle.

    Note de nommage : l'issue cite Search-03b-PatternDatabases-Python.ipynb et Search-03d-WeightedAstar-Python.ipynb ; dans l'arbre, les carnets Python sont Search-03b-PatternDatabases.ipynb et Search-03d-WeightedAstar.ipynb, les variantes -CSharp etant les jumelles .NET. Le perimetre est pose sur les noms reels.

  5. jsboige commented on Oct 21, 2026

    @jsboige
    OwnerAuthor

    [DELIVERED] lane myia-ai-01:CoursIA-2 -- PR #21740

    Les quatre criteres de l'issue sont couverts :

    1. Greedy graph-search complet — la ligne du tableau recapitulatif (cell 57) est scindee en tree-search (Non) et graph-search avec ensemble ferme (Oui sur graphe fini a successeurs finis), avec note de portee en cell 9 ; le tableau calcule (cell 56) affiche Oui (graphe fini).
    2. IDA* — la profondeur de pile maximale est reellement mesuree (node.depth + 1, noeuds simultanement tenus sur la pile) et passee au slot max_frontier_size ; le nombre d'iterations est expose a part (attribut iterations, affiche dans display()). Cote C# : correction symetrique (cell 2 + cell 21).
    3. Papermill — les deux carnets re-executes (Papermill 2.6.0, exception: None, 0 erreur, aucun execution_count a null) ; log frais joint au body de la PR.
    4. Jumeaux verifies — balayage de toute la famille Search-03* (10 carnets) : aucun carnet tiers ne porte les memes defauts (le ida_star de Search-03b a une autre signature et ne renvoie pas de SearchResult), aucune issue sceur a ouvrir.

    Sorties : seules les cellules dont la source a change ont ete reimportees (40 et 56 en Python, 22 en C#) ; le reste du .ipynb est byte-identique a main.

    Point d'arbitrage. La PR #21226 (lane myia-po-2024:CoursIA-2, ouverte le 2026-10-17) porte le meme objet et n'est pas mergeable en l'etat : son jumeau C# n'a pas ete re-execute (sortie de la cellule 22 identique a main alors que la cellule 21 a change), et son check Twin parity audit est en echec (entree d'audit 0024 masquee par l'entree 0025 deja sur main — c'est l'index zero-pade qui decide, pas la date). Les deux livraisons sont donc en concurrence sur les memes fichiers ; la retention et la cloture de l'autre PR reviennent au coordinateur, qui a ete informe par DM.

  6. added 6 commits that reference this issue on Oct 21, 2026
  7. added a commit that references this issue on Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions