Skip to content

feat(probas,#14049): DoWhy-3 decouverte de structure — organes causal-learn (PC/GES/LiNGAM), verdict CPDAG - #15886

Merged
jsboige merged 1 commit into
mainfrom
feature/14049-dowhy3-structure-discovery
Sep 13, 2026
Merged

jsboige merged 1 commit into
mainfrom
feature/14049-dowhy3-structure-discovery

Conversation

@jsboige

@jsboige jsboige commented Sep 13, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/notebook-python — lane myia-po-2023:CoursIA — prev: MED/guard #15850

Summary

Grain DoWhy-3 de la série DoWhy (#14049) : la découverte de structure — le graphe qu'on n'a pas. Répond à la question laissée ouverte par DoWhy-1 §4 (« le graphe assumé ») : que retrouve-t-on du DAG causal depuis les données seules, et où s'arrête exactement ce que les données peuvent trancher ?

4 fichiers (1 sujet, +1981/−1) :

  • dowhy_discovery_organs.py — organe canonique importable (contrainte d'architecture feat(ict,#13903): Greffe 5 tranche 2/3 -- adaptateurs cross-engine Quasi-Experimental + PyMC-05 #13921 : module source canonique → {notebook, ICT}, jamais de duplication cell-scoped). Expose : generer_donnees_decouverte (DGP 5 variables à bruit gaussien ou non gaussien), executer_pc / executer_ges / executer_lingam (causal-learn réellement exécuté — règle F / SOTA-OK), v_structures, enumerer_extensions_acycliques, verdict_cpdag, comparer_au_dag_vrai, effet_backdoor_depuis_aretes (pont dowhy : du graphe découvert à l'estimand).
  • DoWhy-3-Decouverte-de-Structure.ipynb — 32 cellules, 9 sections, 3 exercices stubbés (convention C.1, sans erreur volontaire).
  • tests/test_dowhy_discovery_organs.py — 19 tests PASS : le consommateur externe exigé par l'acceptance 4, incluant 2 tests anti-dérive (le notebook consomme l'organe, DGP byte-identique).
  • README.md — ligne stack causal-learn, rangée Contenu DoWhy-3, bloc « Exercices de DoWhy-3 ».

Acceptance #14049 (par notebook)

# Critère Preuve
1 Kernel coursia-ml-training, exécution réelle, SOTA-OK notebook_tools.py execute SUCCESS 15,6 s ; 12/12 cellules code execution_count non nul, 0 erreur (vérifié par re-lecture JSON). causal-learn + dowhy importés et exécutés, aucune réimplémentation jouet
2 ≥3 exercices, stubs C.1 3 exercices (resultats_exN = None # TODO etudiant) ; grep -E "raise NotImplementedError|assert False|1/0" = 0
3 Verdict honnête verdict_cpdag rend CPDAG_AMBIGU (« l'ambiguïté est un résultat ») et DAG_ORIENTE avec message de prudence (« l'orientation vient des hypothèses, pas des données seules ») ; section 6 dédie à l'échec silencieux de LiNGAM sur bruit gaussien (DAG complet, faux, instable inter-seeds — mesuré sur 2 seeds)
4 API canonique importable + consommateur externe le notebook consomme ddo.* ; tests/test_dowhy_discovery_organs.py (19 PASS) appelle l'organe directement + anti-dérive byte-identique
5 Entrée README constellation rangée Contenu + bloc exercices + stack (même forme que les tranches DoWhy-2/DoWhy-5 déjà mergées)

Résultats enseignés (tous mesurés avant l'écriture, scan 20 seeds)

  • PC (α=0.01) et GES rendent le CPDAG canonique 20/20 seeds : squelette 5/5, v-structure C→Y←M orientée, C–X et X–M ambiguës — la classe d'équivalence de Markov comme borne structurelle (augmenter n ne tranche pas).
  • LiNGAM (bruit non gaussien) recouvre le DAG exact 10/10 seeds (5/5 arêtes, ordre causal exact) ; sur bruit gaussien il rend un DAG complet, faux et instable inter-seeds, sans erreur ni avertissement.
  • 3 extensions valides, pas 4 : l'orientation C→X + M→X est exclue car elle crée la v-structure C→X←M que la donnée exclut — enumerer_extensions_acycliques vérifie acyclicité et conservation des v-structures.
  • L'ambiguïté se propage à l'estimand : les 3 extensions du même CPDAG, sur les mêmes données, donnent 3 estimands dowhy distincts (0.812 / 0.219 / 1.046 pour un effet total vrai de 0.8) avec 3 ensembles d'ajustement ({C}, {M}, {}).

Design note (mesure préalable) : COEF_C_Y = 0.3 et non 0.6 — à 0.6, la covariance partielle (C, M \| Y) s'annule presque exactement (cancellation du chemin C→X→M contre l'ouverture du collisionneur C→Y←M) : monde quasi-infidèle où PC perd la v-structure 18/20 seeds. À 0.3, corr partielle ≈ 0.27 : v-structure retrouvée 20/20 à α=0.01. La fragilité à α=0.05 (15/20) devient la matière de l'exercice 2.

Tests

pytest tests/test_dowhy_discovery_organs.py : 19 passed (env coursia-ml-training, exécution réelle des trois algorithmes — pas de mock, H.1).

Validation

  • notebook_tools.py execute : SUCCESS, validate : OK, 0 warning, 0 erreur.
  • H.3 : 12/12 cellules code avec execution_count + outputs cohérents (les 3 stubs d'exercices s'exécutent sans sortie, convention DoWhy-5).
  • Catalogue byte-identique à main (aucun fichier COURSE_CATALOG* dans le diff) ; base 9198cbdbc8 fraîche.

See #14049 — contribution partielle : DoWhy-4 (confondeur non observé, E-value/Rosenbaum) reste à livrer ; DoWhy-2 et DoWhy-5 déjà mergés.

🤖 Generated with Claude Code

…-learn (PC/GES/LiNGAM), verdict CPDAG

Grain DoWhy-3 de la serie DoWhy (#14049) : le graphe qu'on n'a pas.
Repond a la question laissee ouverte par DoWhy-1 section 4 (« le graphe
assume ») : que retrouve-t-on du DAG depuis les donnees seules ?

- dowhy_discovery_organs.py : organe canonique importable (contrainte
  #13921) — generer_donnees_decouverte (DGP 5 variables, bruit gaussien
  vs non gaussien), executer_pc / executer_ges / executer_lingam
  (causal-learn REEL — regle F / SOTA-OK), v_structures,
  enumerer_extensions_acycliques, verdict_cpdag, comparer_au_dag_vrai,
  effet_backdoor_depuis_aretes (pont dowhy).
- DoWhy-3-Decouverte-de-Structure.ipynb : 32 cellules executees sur
  kernel coursia-ml-training (12/12 execution_count, 0 erreur, C.1 ok),
  3 exercices stubbes sans erreur volontaire.
- tests/test_dowhy_discovery_organs.py : 19 tests PASS (consommateur
  externe + anti-derive notebook<->organe byte-identique).
- README : ligne stack causal-learn, rangee Contenu DoWhy-3, bloc
  exercices.

Resultats enseignes, tous mesures : PC(alpha=0.01) et GES rendent le
CPDAG canonique 20/20 seeds (C->Y<-M orientee, C--X et X--M ambigues) ;
LiNGAM recouvre le DAG exact 10/10 sous bruit non gaussien et rend un
DAG faux-silencieux instable sous bruit gaussien ; 3 extensions valides
(pas 4 — la v-structure C->X<-M est exclue par la donnee) ; 3 estimands
dowhy differents pour les 3 extensions du meme CPDAG (0.81/0.22/1.05
pour un effet vrai de 0.8).

Design note : COEF_C_Y=0.3 (et non 0.6) — a 0.6 la covariance partielle
(C,M|Y) s'annule presque exactement (quasi-infidelite), PC perd la
v-structure 18/20 seeds ; mesuree par scan avant fixation du DGP.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ No prose/output mismatch detected in the notebooks this PR changed.

Scope = notebooks CHANGED in this PR, not the whole corpus. Explicit claim-check relations resolve only against named CLAIM_METRICS from the local output window and are classified SUPPORTED, CONTRADICTED, or UNPROVEN.
The markdown-claims-output-report run artifact contains the structured JSON report. See python scripts/check_markdown_claims_output.py --help for re-running locally.
Detector rationale: c.290 / c.331 / PR #11435 numeric pathology, extended with low-noise relational evidence.

@github-actions

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 1
  • Code cells validated: 12
  • Result: All passed

Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns)
Non-Python kernels (.NET/Lean): C.1 + errors only (execution_count advisory)
QuantConnect notebooks: C.1 + errors only (require QC Cloud for execution)

@github-actions

Copy link
Copy Markdown
Contributor

Notebook outputs-required (H.4 schema): PASS (every code cell carries an outputs: list)

@github-actions github-actions Bot added the variation-tag-missing PR sans tag Grain: <TIER>/<GENRE> (variation-protocol) label Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Grain tag obligatoire (#10045, bloquant).

Grain tag absent (no Grain: / in body).

Pour passer ce gate, le body doit porter en tete une ligne de la forme :

Grain: <DEEP|MED|LIGHT>/<genre> -- lane <machine:workspace> -- prev: <TIER>/<GENRE> #<PR>

Le <genre> doit figurer dans l'enumeration §1 de variation-protocol.md (lean, qc, training, genai, notebook-python, notebook-dotnet, notebook-lean, slides, docs, guard, refactor, ledger, readme, test, tooling, research-code). Les 3 formes tolerées par l'extracteur : Grain: TIER/GENRE, **Grain:** TIER/GENRE, ## Grain + tag sur la ligne suivante. La lane doit suivre le format <machine>:<workspace> (cf. lane-claim-protocol.md).

@github-actions

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

✅ 8/8 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ✅ SUCCESS 11.7s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 10.2s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 10.7s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 10.2s
Search-01-StateSpace.ipynb ✅ SUCCESS 10.3s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 7.3s
rl_4_multi_armed_bandits.ipynb ✅ SUCCESS 82.4s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 8.8s

Pinned lockfile: scripts/notebook_tools/golden_set.lock.txt (H.7 P3, axe A #4208)

@myia-ai-01

Copy link
Copy Markdown
Collaborator

[TAG POSÉ PAR ai-01] Grain: DEEP/notebook-python — lane myia-po-2023:CoursIA — prev: MED/guard #15850.

Rouge unique lu firsthand : vtr-required-block — Grain tag absent. Rien d'autre. L'édition rejoue les gardes seule.

TIER DEEP, et le litmus le donne sans appel : +1981/-1 sur quatre fichiers, un notebook neuf (DoWhy-3, découverte de structure), un module d'organes dowhy_discovery_organs.py, sa suite de tests, et le README de la série. main gagne une capacité qui n'existait pas — PC/GES/LiNGAM avec verdict CPDAG — et sa production a demandé du raisonnement de domaine. Genre notebook-python : c'est le type de travail, pas le répertoire.

Ce grain tient votre plancher G-VAR-1 (CONTENU) pour le cycle. Il ne peut pas merger avant ~03:38Z (créé 01:38Z, plancher de 120 min) : c'est mécanique et ça ne vous concerne pas. Tirez votre grain suivant.

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: LGTM (vérifié: inspection complète organ + sémantique CPDAG + exec counts 12/12 firsthand)

Revue [Hermes] sur head c2a9df0. Aucune review préexistante sur ce SHA (CI comments seulement).

  • Security scan : grep secrets sur 87,6 Ko de diff — zéro match.
  • Sémantique CPDAG vérifiée : enumerer_extensions_acycliques filtre les 2^k orientations par (acyclicité ET v-structures exactement égales à celles du CPDAG) — c'est précisément la définition d'un membre de la classe d'équivalence de Markov (même squelette par construction + mêmes v-structures). Brute-force exact et lisible sur 5 variables ; le claim « 3 extensions, pas 4 » est couvert par test_extensions_acycliques_exactement_trois. comparer_au_dag_vrai (squelette trié, inversées, parasites/manquantes) et verdict_cpdag (borne de Markov ≠ échec d'algorithme ; orientation LiNGAM vient de l'hypothèse, pas des données) sont conceptuellement justes — pédagogie honnête.
  • Piège gaussien couvert par test : test_lingam_gaussien_rend_un_dag_faux est exactement le warning du verdict — bonne garde anti-complaisance.
  • Notebook : 12/12 execution_count séquentiels 1→12, 0 traceback — cohérent avec le claim SUCCESS 15,6 s du body (pas de claim de figures ici, et 0 png dans le diff : cohérent).
  • Tests (19) : réels, causal-learn exécuté (H.1), anti-dérive byte-identique DGP + cellule PC (alpha=0.01 motivé).
  • CI : Notebook Validation PASS, outputs-required PASS, Golden-Set 8/8, prose-mismatch none.

Même point d'action que #15891 : le gate #10045 signale Grain tag absent — le body porte Grain **DoWhy-3** en prose mais pas la ligne canonique Grain: <TIER>/<GENRE> -- lane <machine:workspace> -- prev: ... en tête. Fix = edit du body.

@github-actions github-actions Bot removed the variation-tag-missing PR sans tag Grain: <TIER>/<GENRE> (variation-protocol) label Sep 13, 2026
@jsboige
jsboige merged commit 71376e0 into main Sep 13, 2026
81 of 84 checks passed
jsboige added a commit that referenced this pull request Sep 13, 2026
Conflit unique (README Causal-Bridges, cf #15891) resolu en UNION :
entree + exercices DoWhy-3 (main, #15886) et DoWhy-4 (branche) gardes
tous les deux, en ordre numerique. Aucune entree retiree de main.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Sep 13, 2026
…e dowhy, robustness value, Rosenbaum (#15891)

Enonce cible : « quelle force devrait avoir un confondeur cache pour
annuler cet effet ? » — un chiffre. Robustness value Cinelli-Hazlett
(linear-partial-R2), E-value natif dowhy + benchmark McGowan-Greevy,
bornes de Rosenbaum exactes (Gamma*), courbe de bascule du confondeur
simule (direct-simulation).

Organe importable dowhy_sensitivity_organs.py (2 mondes DGP, refuters
reellement executes, 4 pieges API dowhy 0.14 encapsules), notebook 39
cellules kernel coursia-ml-training execute (20/20, 0 erreur, 3 figures),
26 tests PASS, rangee + exercices README.

See #14049 (Closes quand #15886 DoWhy-3 sera mergee).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants