SCM.ID
Identification on structural causal models: graphical criteria and theorems (back-door, c-component factorization) stated in SCM terms.
Identifiable 7 core · 1 supporting This file defines the query-level interface used by SCM identification theorems. ★ CausalQuery★ Identifiable★ nonIdentifiable_iff★ IdentifiableUnder★ identifiableUnder_mono
Identifiability
This file defines the query-level interface used by SCM identification theorems.
CausalQuery is a functional of an SCM, obsEquiv compares observational
kernels with heterogeneous equality, Identifiable and NonIdentifiable express
whether a query is a functional of the observational law on a fixed SWIG graph,
and IdentifiableUnder adds functional and structural assumption predicates.
The helper theorems expose witness-based non-identifiability and monotonicity
under stronger assumptions.
A causal query is a functional of a causal model, producing a value in some type α.
Definition (Lean source)
Two SCMs are observationally equivalent if their derived observational kernels agree. Because obsKernel has dependent domain/codomain (FixedValues M and ObservedValues M), we use HEq to accommodate two models whose fixed/observed sets may only be propositionally equal.
A causal query Φ is identifiable from the observational distribution if any two causal models sharing the same SWIG graph and observational kernel must agree on Φ.
Definition (Lean source)
A causal query is non-identifiable if there exist two models with the same SWIG graph and observational kernel but different query values.
Definition (Lean source)
For a SWIG graph G and a causal query Φ, the causal query is non-identifiable from the observational distribution if and only if there exist two causal models with SWIG graph G and the same observational law that disagree on the value of Φ.
Formal statement
Proof (Lean source)
Identifiability given both functional and structural assumptions.
Definition (Lean source)
Monotonicity of identifiability under assumptions. Fix functional-assumption predicates Af₁, Af₂ and structural-assumption predicates As₁, As₂ on causal models sharing a graph G, together with a causal query Φ. If every model satisfying Af₂ also satisfies Af₁, every model satisfying As₂ also satisfies As₁, and Φ is identifiable under the assumption pair (Af₁, As₁), then Φ is identifiable under (Af₂, As₂): passing to the more restrictive assumption predicates Af₂, As₂ cannot destroy identifiability.
Formal statement
Proof (Lean source)
1 supporting declaration (lemmas, instances)
-
identifiable_eq_identifiableUnder_truetheorem — Identifiability without additional assumptions is the special case where both Af and As are trivially satisfied.hypothesesconclusionProof (Lean source)
theorem identifiable_eq_identifiableUnder_true {Ω : N → Type*} [∀ n, MeasurableSpace (Ω n)] {α : Type*} (G : SWIGGraph N) (Φ : CausalQuery N Ω α) : Identifiable G Φ ↔ IdentifiableUnder G (fun _ => True) (fun _ => True) Φ := by simp [Identifiable, IdentifiableUnder]
Overlap 1 core · 0 supporting This file defines the kernel-level overlap condition used by do-calculus identification rules. ★ Rule2JointOverlap
Overlap
This file defines the kernel-level overlap condition used by do-calculus
identification rules. The main predicate, Rule2JointOverlap, requires the
post-intervention marginal on Z.random ∪ W to be absolutely continuous with
respect to the corresponding observational marginal. This continuous-friendly
support condition feeds the kernel-native Rule 2 and the backdoor/frontdoor
identification theorems without imposing pointwise singleton positivity.
Rule 2 joint overlap (canonical, continuous-friendly). Absolute continuity of the (Z.image .random ∪ W)-marginal of (M'.fixSet Z).obsKernel s' w.r.t. the same marginal of M'.obsKernel (fixSetProj s').
Definition (Lean source)
BackdoorCriterion 2 core · 0 supporting This file defines the SWIG backdoor criterion used by SCM backdoor identification and proves the Rule 3 marginal-invariance step for the adjustment set. ★ backdoor_rule3_Z_marginal
Backdoor criterion and Rule 3 marginal leg
This file defines the SWIG backdoor criterion used by SCM backdoor
identification and proves the Rule 3 marginal-invariance step for the adjustment
set. The full backdoor completeness and identifiability theorems live in
Causalean/SCM/ID/Backdoor.lean; this module supplies their reusable graphical
criterion and the Z-marginal equality needed in the do-calculus assembly.
Backdoor criterion of Z relative to (X, Y) in the SWIG graph G.
Definition (Lean source)
Backdoor Rule-3 leg. Fix a causal model M and a treatment set X whose random copy is observed and whose fixed copy is not already held fixed in M, and a set Z that is observed in M such that no node of Z is a descendant of any treatment random node — the non-descendant clause of the backdoor criterion. Then, at any post-intervention configuration s_post, the Z-marginal of the post-intervention observational law at s_post equals the Z-marginal of the original observational law at the pre-intervention configuration underlying s_post.
Formal statement
Proof (Lean source)
Backdoor 6 core · 5 supporting The kernel-equality backdoor_completeness is pointwise in the post-intervention slice, hence pointwise in the treatment value t. ★ backdoor_completeness_ae★ backdoor_identifiable_ae
Backdoor identification, a.e. in the treatment value
The kernel-equality backdoor_completeness is pointwise in the post-intervention slice, hence
pointwise in the treatment value t. For non-atomic (continuous) treatment that statement reads
the conditional obsCondKernel on the measure-zero {X = t} slice, where Mathlib's disintegration
representative is not pinned by the observational law — so the pointwise form is too strong.
This file states the honest, regime-uniform version: the identity holds for νX-almost-every
treatment value t, where νX is the observational treatment marginal, under a standard
positivity / overlap assumption P_X × P_Z ≪ P_{X,Z}. Discrete/atomic treatment is the special
case where νX is atomic, so "a.e. t" is "every positive-mass treatment value".
The proof vehicle is the joint identity νX ⊗ₘ Kdo = νX ⊗ₘ Kbd, from which the
a.e. statement follows by ProbabilityTheory.Kernel.ae_eq_of_compProd_eq.
Main declarations
* SCM.treatmentMarginal — observational treatment marginal νX.
* SCM.BackdoorPositivityAE — product-overlap condition P_X × P_Z ≪ P_{X,Z}.
* SCM.doKernelY and SCM.adjustmentKernelY — treatment-indexed do and
backdoor-adjustment kernels for the outcome block.
* SCM.doKernelY_disintegrate and SCM.doKernelY_marginal_const — chain-rule
and Rule-3 reductions used in the proof.
* SCM.backdoor_completeness_ae_compProd — primary joint-kernel completeness.
* SCM.backdoor_completeness_ae — almost-every treatment-value completeness.
* SCM.backdoor_identifiable_ae — cross-SCM almost-every identifiability.
The observational treatment marginal νX = (M.obsKernel s₀).map π_{X.random}.
Definition (Lean source)
Joint (product) positivity / overlap at base s₀.
Definition (Lean source)
Post-intervention Y-marginal as a kernel in the treatment value t, at base s₀: t ↦ ((M.fixSet X).obsKernel (s_post s₀ t)).map π_Y.
Definition (Lean source)
Backdoor-adjustment Y-marginal as a kernel in the treatment value t, at base s₀.
Definition (Lean source)
Backdoor completeness, a.e. in the treatment value. Fix a causal model M and a treatment set X whose random copy is observed and whose fixed copy is not already held fixed in M, and let Y, Z be observed outcome and adjustment sets, neither of which overlaps the treatment's random nodes, satisfying the backdoor criterion relative to (X,Y). Given a base configuration s0 at which overlap holds along every post-intervention slice and the product of the observational treatment and adjustment-set marginals is absolutely continuous with respect to their joint observational law, then for almost every treatment value t under the observational treatment marginal, the post-intervention outcome distribution at t equals the backdoor-adjustment functional evaluated at t.
Formal statement
Proof (Lean source)
Backdoor identifiability, a.e. in the treatment value (cross-SCM corollary). Fix two causal models M₁, M₂ that share the same SWIG graph and the same observational kernel, with base configurations that agree under this shared identification. Fix a treatment set X valid in both models and disjoint outcome/adjustment sets Y, Z that are observed in both models and disjoint from the treatment's random nodes, such that Z satisfies the backdoor criterion for (X,Y) in each model separately, with overlap holding along every post-intervention slice in each model and product positivity of the observational treatment and adjustment-set marginals holding in each model. Then for almost every treatment value t under the shared observational treatment marginal, the post-intervention outcome distribution computed in M₁ at t equals the one computed in M₂ at t, since each model individually satisfies backdoor completeness and the two share the same graph and observational kernel.
Formal statement
Proof (Lean source)
5 supporting declarations (lemmas, instances)
-
instIsFiniteKernelDoKernelYinstance — The treatment-indexed post-intervention Y-marginal kernel is finite.instance instIsFiniteKernelDoKernelY (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (s0 : M.FixedValues) : IsFiniteKernel (M.doKernelY X hObs hFix Y hY s0) := by rw [SCM.doKernelY]; infer_instance -
instIsFiniteKernelAdjustmentKernelYinstance — The treatment-indexed backdoor-adjustment Y-marginal kernel is finite.instance instIsFiniteKernelAdjustmentKernelY (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y Z : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hZ : Z ⊆ M.observed) (s0 : M.FixedValues) : IsFiniteKernel (M.adjustmentKernelY X hObs hFix Y Z hY hZ s0) := by rw [SCM.adjustmentKernelY]; infer_instance -
doKernelY_disintegratetheorem — Treatment-indexed chain rule. At treatment value t, the post-do(X) Y-marginal kernel disintegrates through Z: it is the conditional Y ∣ Z (under do(X)) composed with the post-do(X) Z-marginal kernel. The doKernelY-level form of obsKernel_map_eq_obsCondKernel_comp.hypothesesM :SCM N ΩX :Finset NhObs :∀ D ∈ X, SWIGNode.random D ∈ M.observedhFix :∀ D ∈ X, SWIGNode.fixed D ∉ M.fixedhY :Y ⊆ M.observedhZ :Z ⊆ M.observeds0 :M.FixedValuesconclusionM.doKernelY X hObs hFix Y hY s0 t= ((M.fixSet X hObs hFix).obsCondKernel Y Z ((SCM.fixSet_observed M X hObs hFix).symm ▸ hY) ((SCM.fixSet_observed M X hObs hFix).symm ▸ hZ)).sectR (M.fixSetExtend X hObs hFix s0 t) ∘ₘ M.doKernelY X hObs hFix Z hZ s0 tProof (Lean source)
theorem doKernelY_disintegrate (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y Z : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hZ : Z ⊆ M.observed) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : M.doKernelY X hObs hFix Y hY s0 t = ((M.fixSet X hObs hFix).obsCondKernel Y Z ((SCM.fixSet_observed M X hObs hFix).symm ▸ hY) ((SCM.fixSet_observed M X hObs hFix).symm ▸ hZ)).sectR (M.fixSetExtend X hObs hFix s0 t) ∘ₘ M.doKernelY X hObs hFix Z hZ s0 t := by have hY' : M.doKernelY X hObs hFix Y hY s0 t = ((M.fixSet X hObs hFix).obsKernel (M.fixSetExtend X hObs hFix s0 t)).map (valuesProjection ((SCM.fixSet_observed M X hObs hFix).symm ▸ hY)) := by rw [SCM.doKernelY, ProbabilityTheory.Kernel.map_apply _ (measurable_valuesProjection _), ProbabilityTheory.Kernel.comap_apply] have hZ' : M.doKernelY X hObs hFix Z hZ s0 t = ((M.fixSet X hObs hFix).obsKernel (M.fixSetExtend X hObs hFix s0 t)).map (valuesProjection ((SCM.fixSet_observed M X hObs hFix).symm ▸ hZ)) := by rw [SCM.doKernelY, ProbabilityTheory.Kernel.map_apply _ (measurable_valuesProjection _), ProbabilityTheory.Kernel.comap_apply] rw [hY', hZ'] exact SCM.obsKernel_map_eq_obsCondKernel_comp (M.fixSet X hObs hFix) Y Z _ _ _ -
doKernelY_marginal_consttheorem — Treatment-indexed Rule 3 (marginal invariance). If no X-copy is an ancestor of any Z-node, the post-do(X) Z-marginal kernel is constant in the treatment value and equals the observational Z-marginal at base s₀. The doKernelY-level form of backdoor_rule3_Z_marginal.hypothesesM :SCM N ΩX :Finset NhObs :∀ D ∈ X, SWIGNode.random D ∈ M.observedhFix :∀ D ∈ X, SWIGNode.fixed D ∉ M.fixedhZ :Z ⊆ M.observedh_noanc :∀ z ∈ Z, ∀ D ∈ X, ¬ M.toSWIGGraph.dag.isAncestor (SWIGNode.random D) zs0 :M.FixedValuesconclusionM.doKernelY X hObs hFix Z hZ s0 t = (M.obsKernel s0).map (valuesProjection hZ)Proof (Lean source)
theorem doKernelY_marginal_const (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Z : Finset (SWIGNode N)) (hZ : Z ⊆ M.observed) (h_noanc : ∀ z ∈ Z, ∀ D ∈ X, ¬ M.toSWIGGraph.dag.isAncestor (SWIGNode.random D) z) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : M.doKernelY X hObs hFix Z hZ s0 t = (M.obsKernel s0).map (valuesProjection hZ) := by have hZ' : M.doKernelY X hObs hFix Z hZ s0 t = ((M.fixSet X hObs hFix).obsKernel (M.fixSetExtend X hObs hFix s0 t)).map (valuesProjection ((SCM.fixSet_observed M X hObs hFix).symm ▸ hZ)) := by rw [SCM.doKernelY, ProbabilityTheory.Kernel.map_apply _ (measurable_valuesProjection _), ProbabilityTheory.Kernel.comap_apply] rw [hZ'] have hR3 := SCM.backdoor_rule3_Z_marginal M X hObs hFix Z hZ h_noanc (M.fixSetExtend X hObs hFix s0 t) rw [SCM.fixSetProj_fixSetExtend] at hR3 exact hR3 -
backdoor_completeness_ae_compProdtheorem — Joint (compProd) completeness — primary form.hypothesesM :SCM N ΩX :Finset NhObs :∀ D ∈ X, SWIGNode.random D ∈ M.observedhFix :∀ D ∈ X, SWIGNode.fixed D ∉ M.fixedhY :Y ⊆ M.observedhZ :Z ⊆ M.observed_h_bd :M.toSWIGGraph.backdoorCriterion X hObs hFix Y ZhDisj_YXr :Disjoint Y (X.image SWIGNode.random)hDisj_XrZ :Disjoint (X.image SWIGNode.random) Zs0 :M.FixedValueshOverlap :∀ s : (M.fixSet X hObs hFix).FixedValues,Rule2JointOverlap M X hObs hFix Z (union_subset (Finset.image_subset_iff.mpr hObs) hZ) s_hPositivity :M.BackdoorPositivityAE X Z hZ (union_subset (Finset.image_subset_iff.mpr hObs) hZ) s0conclusion(M.treatmentMarginal X (Finset.subset_union_left.trans (union_subset (Finset.image_subset_iff.mpr hObs) hZ)) s0) ⊗ₘ (M.doKernelY X hObs hFix Y hY s0)= (M.treatmentMarginal X (Finset.subset_union_left.trans (union_subset (Finset.image_subset_iff.mpr hObs) hZ)) s0) ⊗ₘ (M.adjustmentKernelY X hObs hFix Y Z hY hZ s0)Proof (Lean source)
theorem backdoor_completeness_ae_compProd (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y Z : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hZ : Z ⊆ M.observed) (_h_bd : M.toSWIGGraph.backdoorCriterion X hObs hFix Y Z) (hDisj_YXr : Disjoint Y (X.image SWIGNode.random)) (hDisj_XrZ : Disjoint (X.image SWIGNode.random) Z) (s0 : M.FixedValues) (hOverlap : ∀ s : (M.fixSet X hObs hFix).FixedValues, Rule2JointOverlap M X hObs hFix Z (union_subset (Finset.image_subset_iff.mpr hObs) hZ) s) (_hPositivity : M.BackdoorPositivityAE X Z hZ (union_subset (Finset.image_subset_iff.mpr hObs) hZ) s0) : (M.treatmentMarginal X (Finset.subset_union_left.trans (union_subset (Finset.image_subset_iff.mpr hObs) hZ)) s0) ⊗ₘ (M.doKernelY X hObs hFix Y hY s0) = (M.treatmentMarginal X (Finset.subset_union_left.trans (union_subset (Finset.image_subset_iff.mpr hObs) hZ)) s0) ⊗ₘ (M.adjustmentKernelY X hObs hFix Y Z hY hZ s0) := by have hXrZ : X.image SWIGNode.random ∪ Z ⊆ M.observed := union_subset (Finset.image_subset_iff.mpr hObs) hZ have hXr : X.image SWIGNode.random ⊆ M.observed := Finset.subset_union_left.trans hXrZ -- Abbreviations. set sT := fun t => M.fixSetExtend X hObs hFix s0 t with hsT set hZ_post : Z ⊆ (M.fixSet X hObs hFix).observed := (SCM.fixSet_observed M X hObs hFix).symm ▸ hZ with hZpost_def set hY_post : Y ⊆ (M.fixSet X hObs hFix).observed := (SCM.fixSet_observed M X hObs hFix).symm ▸ hY with hYpost_def -- μZ = (M.obsKernel s0).map projZ, the observational Z-marginal at base s0. set μZ := (M.obsKernel s0).map (valuesProjection hZ) with hμZ -- ============================================================ -- Reduction 1 (chain rule + Rule 3): the do-side Y-marginal kernel at t. -- doKernelY t = (sectR (fixSet X).obsCondKernel (sT t)) ∘ₘ μZ -- ============================================================ -- Reduction 1 (chain rule + Rule 3) is now packaged in the treatment-indexed -- do-calculus lemmas `doKernelY_disintegrate` and `doKernelY_marginal_const`. have hLHS : ∀ t, M.doKernelY X hObs hFix Y hY s0 t = ((M.fixSet X hObs hFix).obsCondKernel Y Z hY_post hZ_post).sectR (sT t) ∘ₘ μZ := by intro t rw [doKernelY_disintegrate M X hObs hFix Y Z hY hZ s0 t, doKernelY_marginal_const M X hObs hFix Z hZ _h_bd.2.2.2.1 s0 t] -- ============================================================ -- Reduction 2 (unfold backdoorAdjustment): the adjustment-side kernel at t. -- adjustmentKernelY t = (sectR condPost (sT t)) ∘ₘ μZ -- where condPost z = M.obsCondKernel Y (Xr∪Z) (s0, fillZrW (sT t) z). -- ============================================================ -- The `condPost` kernel appearing in `backdoorAdjustment`. set hXZ : X.image SWIGNode.random ∪ Z ⊆ M.observed := hXrZ with hXZ_def set condPost : Kernel ((M.fixSet X hObs hFix).FixedValues × ValuesOn Z (swigΩ Ω)) (ValuesOn Y (swigΩ Ω)) := (M.obsCondKernel Y (X.image SWIGNode.random ∪ Z) hY hXZ).comap (fun p : (M.fixSet X hObs hFix).FixedValues × ValuesOn Z (swigΩ Ω) => (M.fixSetProj X hObs hFix p.1, M.fillZrW X hObs hFix Z p.1 p.2)) (prodMk ((M.measurable_fixSetProj X hObs hFix).comp measurable_fst) (M.measurable_fillZrW_prod X hObs hFix Z)) with hcondPost_def haveI : IsMarkovKernel (M.obsCondKernel Y (X.image SWIGNode.random ∪ Z) hY hXZ) := by unfold SCM.obsCondKernel; infer_instance haveI : IsMarkovKernel condPost := by rw [hcondPost_def]; infer_instance have hRHS : ∀ t, M.adjustmentKernelY X hObs hFix Y Z hY hZ s0 t = condPost.sectR (sT t) ∘ₘ μZ := by intro t -- adjustmentKernelY t = backdoorAdjustment (sT t). have hadj : M.adjustmentKernelY X hObs hFix Y Z hY hZ s0 t = M.backdoorAdjustment X hObs hFix Y Z hY hZ (sT t) := by rw [SCM.adjustmentKernelY, ProbabilityTheory.Kernel.comap_apply] rw [hadj] -- Unfold backdoorAdjustment body to ((zMarginalPost ⊗ₖ condPost).map snd) (sT t). change ((((M.obsKernel.map (valuesProjection hZ)).comap (M.fixSetProj X hObs hFix) (M.measurable_fixSetProj X hObs hFix)) ⊗ₖ condPost).map snd) (sT t) = condPost.sectR (sT t) ∘ₘ μZ rw [compProd_map_snd_apply, ProbabilityTheory.Kernel.comap_apply, ProbabilityTheory.Kernel.map_apply _ (measurable_valuesProjection _), SCM.fixSetProj_fixSetExtend, ← hμZ] -- ============================================================ -- a.e. Rule 2 on the product νX ⊗ₘ const μZ. -- ============================================================ -- νX = treatmentMarginal = (M.obsKernel s0).map projXr. set νX := M.treatmentMarginal X hXr s0 with hνX have hνX_eq : νX = (M.obsKernel s0).map (valuesProjection hXr) := by rw [hνX, SCM.treatmentMarginal] -- The product measure λ = νX ⊗ₘ const μZ. set lam := νX ⊗ₘ const _ μZ with hlam -- Finiteness instances. haveI : IsFiniteMeasure νX := by rw [hνX_eq]; exact (M.obsKernel s0).isFiniteMeasure_map _ haveI : IsFiniteMeasure μZ := by rw [hμZ]; exact (M.obsKernel s0).isFiniteMeasure_map _ -- Apply the a.e. Rule 2 with Z := X, W := Z. have hPos_ae : (((M.obsKernel s0).map (valuesProjection hXr) ⊗ₘ const _ ((M.obsKernel s0).map (valuesProjection hZ))).map (fun p => valuesUnionMk p.1 p.2)) ≪ ((M.obsKernel s0).map (valuesProjection hXrZ)) := _hPositivity -- Rule 2 straight from the backdoor criterion: the applicator derives the -- d-separation + non-descendance premises internally. have hR2 := SCM.backdoor_rule2_ae M X hObs hFix Y Z hY hZ hXr hXrZ hDisj_YXr hDisj_XrZ _h_bd s0 hOverlap hPos_ae haveI hdoKfin : IsFiniteKernel (M.doKernelY X hObs hFix Y hY s0) := by rw [SCM.doKernelY]; infer_instance haveI hadjSF : IsSFiniteKernel (M.adjustmentKernelY X hObs hFix Y Z hY hZ s0) := by rw [SCM.adjustmentKernelY, SCM.backdoorAdjustment]; infer_instance set liftTZ : ValuesOn (X.image SWIGNode.random) (swigΩ Ω) × ValuesOn Z (swigΩ Ω) → (M.fixSet X hObs hFix).FixedValues × ValuesOn Z (swigΩ Ω) := fun p => (sT p.1, p.2) with hliftTZ_def have hliftTZ_meas : Measurable liftTZ := by rw [hliftTZ_def, hsT] exact prodMk ((M.measurable_fixSetExtend X hObs hFix s0).comp measurable_fst) measurable_snd set fL : Kernel (ValuesOn (X.image SWIGNode.random) (swigΩ Ω) × ValuesOn Z (swigΩ Ω)) (ValuesOn Y (swigΩ Ω)) := ((M.fixSet X hObs hFix).obsCondKernel Y Z hY_post hZ_post).comap liftTZ hliftTZ_meas with hfL_def set fR : Kernel (ValuesOn (X.image SWIGNode.random) (swigΩ Ω) × ValuesOn Z (swigΩ Ω)) (ValuesOn Y (swigΩ Ω)) := condPost.comap liftTZ hliftTZ_meas with hfR_def have hL : ∀ t, M.doKernelY X hObs hFix Y hY s0 t = (fL.sectR t) ∘ₘ μZ := by intro t exact hLHS t have hR : ∀ t, M.adjustmentKernelY X hObs hFix Y Z hY hZ s0 t = (fR.sectR t) ∘ₘ μZ := by intro t exact hRHS t have hae : ∀ᵐ p ∂(νX ⊗ₘ const (ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) μZ), fL p = fR p := by rw [hνX_eq, hμZ] filter_upwards [hR2] with p hp simpa [hfL_def, hfR_def, hliftTZ_def, hcondPost_def, hsT, ProbabilityTheory.Kernel.comap_apply, SCM.fixSetProj_fixSetExtend, SCM.fillZrW_fixSetExtend] using hp exact compProd_eq_of_inner_ae νX μZ (M.doKernelY X hObs hFix Y hY s0) (M.adjustmentKernelY X hObs hFix Y Z hY hZ s0) fL fR hL hR hae
Query 8 core · 1 supporting This file contains the lightweight query-level API shared by ID soundness theorems. ★ interventionalQuery_eq_doKernelY_of_valid★ interventionalQueryValid_iff_of_toSWIGGraph_eq
Total interventional query API
This file contains the lightweight query-level API shared by ID soundness
theorems. It deliberately avoids importing the Tian/c-factor ID skeleton, so
modules can state and prove base cases for interventionalQuery without
depending on the full density recovery stack.
Every random or fixed SWIG-node value space is nonempty when every base-node value space is nonempty.
Definition (Lean source)
A finite coordinate product of SWIG-node value spaces is nonempty when all base-node value spaces are nonempty.
Definition (Lean source)
This fixed fallback kernel is used only outside the standard identification query domain.
Definition (Lean source)
A standard structural causal model has a canonical fixed-value assignment.
Definition (Lean source)
This predicate states when the interventional query is in its meaningful standard-model branch.
Definition (Lean source)
The interventional query returns the post-intervention outcome law as a kernel indexed by treatment values.
Definition (Lean source)
For treatment nodes X and outcome nodes Y satisfying the well-formedness conditions for a valid interventional query in a model M, the total interventional query evaluated at M equals the post-intervention outcome-marginal kernel doKernelY.
Formal statement
Proof (Lean source)
Well-formedness invariance under matching SWIG graphs. For an intervention target set X and outcome set Y, if two structural causal models M₁, M₂ have the same SWIG graph, then they agree on whether the total interventional query for X, Y is well formed.
Formal statement
Proof (Lean source)
1 supporting declaration (lemmas, instances)
-
interventionalQuery_eq_default_of_not_validlemma — Outside the well-formed branch, the total interventional query is the fixed fallback kernel.hypothesesconclusioninterventionalQuery (Ω := Ω) X Y M = defaultInterventionalKernel (Ω := Ω) X YProof (Lean source)
lemma interventionalQuery_eq_default_of_not_valid [∀ n, Nonempty (Ω n)] (X : Finset N) (Y : Finset (SWIGNode N)) (M : SCM N Ω) (h : ¬ interventionalQueryValid X Y M) : interventionalQuery (Ω := Ω) X Y M = defaultInterventionalKernel (Ω := Ω) X Y := by classical rw [interventionalQuery] exact dif_neg (by simpa [interventionalQueryValid] using h)
DoLawTransport 2 core · 0 supporting The post-intervention Y-marginal kernel doKernelY is built from the do-observational law (M.fixSet X).obsKernel by a comap (extend the fixed slice by the treatment value) followed by a map (project to the outcomes Y): do ★ doKernelY_eq_of_doObsKernel_heq
Structural transport of the do-observational law to doKernelY
The post-intervention Y-marginal kernel doKernelY is built from the
do-observational law (M.fixSet X).obsKernel by a comap (extend the fixed
slice by the treatment value) followed by a map (project to the outcomes Y):
doKernelY M X … Y … s₀ = ((M.fixSet X).obsKernel.comap (fixSetExtend s₀)).map π_Y.
The comap/map data (fixSetExtend, the Y-projection) and the
intermediate value-space types depend on M only through its SWIG graph
(observed, fixed, which fixSet preserves/enlarges structurally) and the base
slice s₀. Therefore two models sharing a SWIG graph whose do-observational laws
agree produce the same doKernelY.
This isolates the genuine identification content — that the do-observational laws
agree — from the purely structural transport performed here. The identification
content is discharged elsewhere (the Tian g-formula in
GraphicalThms/DoGFormula and its recursive/discrete soundness layers); this file
is graph/measure bookkeeping only and makes no appeal to idSucceeds or any
reference measure.
The Y-marginal of the do-observational law: push (M.fixSet X).obsKernel forward along the projection to the outcome coordinates Y. This is the only part of the do-law that the post-intervention Y-marginal kernel doKernelY depends on — doKernelY is this marginal, reindexed in the treatment value by the comap extension. Crucially this is the identifiable object: the full do-law over all observed nodes is not a functional of the observational law, but its Y-marginal (more precisely its An_{G_X}(Y)-marginal, of which this is a further projection) is.
Definition (Lean source)
Structural transport. Fix two causal models that share the same underlying SWIG graph, together with a treatment set X that is a valid intervention in the first model — every node of X is observed and not already fixed there and likewise valid in the second model, and an outcome set Y that is observed in the first model and observed in the second. If the two models' base fixed-value slices coincide and their Y-marginals of the do-observational law agree, up to the type-level identification the shared graph provides, then the resulting post-intervention Y-marginal kernels doKernelY agree at that shared base slice.
Formal statement
Proof (Lean source)
Adjustment 4 core · 3 supporting This file defines graph-level adjustment functionals for backdoor and frontdoor identification. ★ backdoorAdjustment_invariant★ frontdoorAdjustment_invariant
Adjustment Functionals
This file defines graph-level adjustment functionals for backdoor and frontdoor identification. These functionals express post-intervention outcome distributions in terms of observational kernels, enabling single-model completeness arguments to be combined with cross-model invariance statements. It also proves finite-kernel instances and cross-SCM invariance for both adjustment functionals.
Backdoor adjustment functional.
Definition (Lean source)
Frontdoor adjustment functional.
Definition (Lean source)
Cross-SCM invariance of backdoorAdjustment. Fix two causal models M₁ and M₂ that share the same SWIG graph and the same observational kernel, and a treatment set X, an outcome set Y, and an adjustment set Z that are valid intervention data and observed variables in both models. Then the backdoor-adjustment kernel for Y given Z after intervening on X, computed within M₁, is the same as the one computed within M₂.
Formal statement
Proof (Lean source)
Cross-SCM invariance of frontdoorAdjustment. Fix two causal models M₁ and M₂ that share the same SWIG graph and the same observational kernel, and a treatment set X, an outcome set Y, and a mediator set Z that are valid intervention data and observed variables in both models. Then the frontdoor-adjustment kernel for Y through mediator Z after intervening on X, computed within M₁, is the same as the one computed within M₂.
Formal statement
Proof (Lean source)
3 supporting declarations (lemmas, instances)
-
instIsMarkovKernelObsCondKernelinstance — The observational conditional kernel obsCondKernel Y CC is a Markov kernel (its values are probability measures), inherited from Mathlib's condKernel.instance instIsMarkovKernelObsCondKernel (M : SCM N Ω) (Y CC : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hCC : CC ⊆ M.observed) : IsMarkovKernel (M.obsCondKernel Y CC hY hCC) := by unfold SCM.obsCondKernel; infer_instance -
instIsFiniteKernelBackdoorAdjustmentinstance — The backdoor-adjustment functional is a finite kernel (a compProd of finite kernels, pushed through Prod.snd).instance instIsFiniteKernelBackdoorAdjustment (M : SCM N Ω) (X : Finset N) (hX_obs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hX_fixed : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y Z : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hZ : Z ⊆ M.observed) : IsFiniteKernel (M.backdoorAdjustment X hX_obs hX_fixed Y Z hY hZ) := by rw [SCM.backdoorAdjustment]; infer_instance -
instIsFiniteKernelFrontdoorAdjustmentinstance — The frontdoor-adjustment functional is a finite kernel (nested compProds of finite kernels, pushed through Prod.snd).instance instIsFiniteKernelFrontdoorAdjustment (M : SCM N Ω) (X : Finset N) (hX_obs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hX_fixed : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y Z : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hZ : Z ⊆ M.observed) : IsFiniteKernel (M.frontdoorAdjustment X hX_obs hX_fixed Y Z hY hZ) := by rw [SCM.frontdoorAdjustment]; infer_instance
Frontdoor 4 core · 3 supporting This file states the frontdoor completeness / identification result tying the graph-level functional SCM.frontdoorAdjustment (defined in SCM/ID/Adjustment.lean) to the true post-intervention Y-marginal (M.fixSet X).obsKe ★ frontdoor_completeness_ae_compProd★ frontdoor_identifiable_ae
Frontdoor identification, a.e. in the treatment value
This file states the frontdoor completeness / identification result tying the
graph-level functional SCM.frontdoorAdjustment (defined in SCM/ID/Adjustment.lean)
to the true post-intervention Y-marginal (M.fixSet X).obsKernel.map π_Y, under the
three frontdoor graph clauses recorded by SWIGGraph.frontdoorCriterion.
It is the frontdoor analogue of SCM/ID/Backdoor.lean, and is stated in the same
regime-uniform a.e. style: the identity holds for νX-almost-every treatment value
t (where νX is the observational treatment marginal), via the version-safe joint
identity νX ⊗ₘ Kdo = νX ⊗ₘ Kfd (ProbabilityTheory.Kernel.ae_eq_of_compProd_eq).
Mediator representation
The mediator set is a base node set W : Finset N (so that it is intervenable
— the frontdoor derivation routes through do(W)). Wherever frontdoorAdjustment
expects a Finset (SWIGNode N) mediator it is instantiated at W.image SWIGNode.random.
Proof skeleton (for the main theorem; do-calculus Rules 2 and 3)
Pearl's derivation, in three legs, mirrored at the kernel level:
* Leg A — mediator (Rule 2, FD2). P(Z | do(X)) = P(Z | X): the Z-marginal of
the post-intervention kernel equals the observational conditional P(Z | X = x_do),
because there is no unblocked back-door path X → Z (the fd_no_backdoor_XZ clause).
State this leg νX-a.e. (or in compProd form), never pointwise in the treatment
slice — the pointwise conditional reads obsCondKernel on a νX-null {X = t}
slice and is too strong for continuous treatment (see SCM/ID/Backdoor.lean).
* Leg B — outcome (FD1 + FD3). Because Z intercepts every directed X → Y
path (criterion fd_intercept), P(Y | do(X), Z) = P(Y | do(Z)); and since X
is a valid back-door adjustment set for Z → Y (criterion fd_backdoor_ZY),
P(Y | do(Z)) = ∫_{x'} P(Y | X = x', Z) dP(x'). This leg is exactly
backdoor_completeness_ae_compProd instantiated with treatment := W,
adjustment set := X.image SWIGNode.random, outcome := Y.
* Composition. Chaining Leg A and Leg B reproduces the frontdoorAdjustment
body ∫_z (∫_{x'} P(Y | X=x', Z=z) dP(x')) dP(Z | X=x_do).
The FD1 bridge is exposed as an explicit compProd substrate hypothesis, keeping the theorem focused on assembling the frontdoor functional from Rule 2, Rule 3, and the backdoor marginal-invariance leg rather than re-deriving disintegration inside the final theorem.
frontdoorCriterion says that the base mediator set W satisfies Pearl's frontdoor criterion for treatment variables X and outcome nodes Y: the mediator random nodes intercept every directed treatment-outcome path, have no open back-door path from treatment, admit treatment adjustment for the mediator-outcome effect, and are excluded from the treatment and outcome sets.
Definition (Lean source)
Frontdoor-adjustment Y-marginal as a kernel in the treatment value t, at base s₀ — the frontdoor analogue of adjustmentKernelY. Reindexes the graph-level frontdoorAdjustment (with mediator Z := W.image SWIGNode.random) along fixSetExtend s₀, so its input is the treatment value t rather than the full post-intervention slice.
Definition (Lean source)
Frontdoor completeness — joint (compProd), version-safe primary form. Let X be a valid intervention set — observed and not already fixed, and Wbase likewise a valid intervention set of mediators, with the outcome set Y observed, the random copies of Wbase observed, and the random copies of X observed. Suppose the frontdoor criterion holds for (X, Wbase, Y), that Y is disjoint from the random copies of Wbase and the random copies of Wbase are disjoint from those of X, and that each of the three legs of the frontdoor decomposition — the do(X) leg, the do(Wbase) leg adjusting for X, and the nested do(X)-then-do(Wbase) leg — satisfies the matching backdoor overlap and positivity conditions. Then the joint law of the treatment marginal with the post-intervention Y-marginal equals the joint law of the treatment marginal with the frontdoor-adjustment functional.
Formal statement
Proof (Lean source)
Frontdoor identification, a.e. in the treatment value. Let X be a valid intervention set — observed and not already fixed, and Wbase likewise a valid intervention set of mediators, with the outcome set Y observed, the random copies of Wbase observed, and the random copies of X observed. Suppose the frontdoor criterion holds for (X, Wbase, Y), that Y is disjoint from the random copies of Wbase and the random copies of Wbase are disjoint from those of X, and that each of the three legs of the frontdoor decomposition — the do(X) leg, the do(Wbase) leg adjusting for X, and the nested do(X)-then-do(Wbase) leg — satisfies the matching backdoor overlap and positivity conditions. Then for treatmentMarginal-almost-every treatment value t, the post-intervention Y-marginal doKernelY at t equals the frontdoor-adjustment functional frontdoorKernelY at t.
Formal statement
Proof (Lean source)
3 supporting declarations (lemmas, instances)
-
instIsFiniteKernelFrontdoorKernelYinstance — The treatment-indexed frontdoor-adjustment Y-marginal kernel is finite.instance instIsFiniteKernelFrontdoorKernelY (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hW : W ⊆ M.observed) (s0 : M.FixedValues) : IsFiniteKernel (M.frontdoorKernelY X hObs hFix Y W hY hW s0) := by rw [SCM.frontdoorKernelY]; infer_instance -
obsKernel_map_proj_eq_of_equivlemma — Structurally equivalent structural causal models assign the same observational marginal law to a shared set of observed variables when their fixed-variable assignments correspond.hypothesesM₁ M₂ :SCM N Ωh :SCM.Equiv M₁ M₂hY₁ :Y ⊆ M₁.observedhY₂ :Y ⊆ M₂.observeds₁ :M₁.FixedValuess₂ :M₂.FixedValueshs :HEq s₁ s₂conclusion(M₁.obsKernel s₁).map (valuesProjection hY₁)= (M₂.obsKernel s₂).map (valuesProjection hY₂)Proof (Lean source)
lemma obsKernel_map_proj_eq_of_equiv {M₁ M₂ : SCM N Ω} (h : SCM.Equiv M₁ M₂) (Y : Finset (SWIGNode N)) (hY₁ : Y ⊆ M₁.observed) (hY₂ : Y ⊆ M₂.observed) (s₁ : M₁.FixedValues) (s₂ : M₂.FixedValues) (hs : HEq s₁ s₂) : (M₁.obsKernel s₁).map (valuesProjection hY₁) = (M₂.obsKernel s₂).map (valuesProjection hY₂) := by -- Extract the `obsKernel` HEq while `h` still has its `Equiv` type. have hok0 : HEq M₁.obsKernel M₂.obsKernel := SCM.Equiv.heq_obsKernel h.1 h.2.2.1 h.2.2.2 obtain ⟨⟨dag₁, fixed₁, observed₁, unobserved₁, fio₁, oi₁, od₁, oou₁, foi₁, fou₁, aic₁, dc₁⟩, eT₁, iota₁, sf₁, mf₁, lD₁, pL₁⟩ := M₁ obtain ⟨⟨dag₂, fixed₂, observed₂, unobserved₂, fio₂, oi₂, od₂, oou₂, foi₂, fou₂, aic₂, dc₂⟩, eT₂, iota₂, sf₂, mf₂, lD₂, pL₂⟩ := M₂ rcases h.1 with ⟨_hEdge, rfl, rfl, rfl⟩ -- After unifying `observed`/`fixed`/`unobserved`, the `FixedValues` and -- `ObservedValues` types coincide, so the `HEq`s collapse to `Eq`. have hs_eq : s₁ = s₂ := eq_of_heq hs subst hs_eq have hok := eq_of_heq hok0 rw [hok] -
adjustmentKernelY_empty_eqlemma — With an empty adjustment set, the outcome adjustment kernel equals the observed conditional kernel of the outcome variables given the treated variables at the same fixed values.hypothesesM :SCM N ΩX :Finset NhObs :∀ D ∈ X, SWIGNode.random D ∈ M.observedhFix :∀ D ∈ X, SWIGNode.fixed D ∉ M.fixedhWr :Wr ⊆ M.observedhXr :X.image SWIGNode.random ⊆ M.observeds0 :M.FixedValuesconclusion= M.obsCondKernel Wr (X.image SWIGNode.random) hWr hXr (s0, t)Proof (Lean source)
lemma adjustmentKernelY_empty_eq (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (Wr : Finset (SWIGNode N)) (hWr : Wr ⊆ M.observed) (hXr : X.image SWIGNode.random ⊆ M.observed) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : M.adjustmentKernelY X hObs hFix Wr (∅ : Finset (SWIGNode N)) hWr (empty_subset _) s0 t = M.obsCondKernel Wr (X.image SWIGNode.random) hWr hXr (s0, t) := by let sTt := M.fixSetExtend X hObs hFix s0 t let zMarginalPost : Kernel (M.fixSet X hObs hFix).FixedValues (ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω)) := (M.obsKernel.map (valuesProjection (empty_subset M.observed))).comap (M.fixSetProj X hObs hFix) (M.measurable_fixSetProj X hObs hFix) haveI : IsMarkovKernel (M.obsCondKernel Wr (X.image SWIGNode.random ∪ (∅ : Finset (SWIGNode N))) hWr (union_subset hXr (empty_subset M.observed))) := by unfold SCM.obsCondKernel infer_instance let condPost : Kernel ((M.fixSet X hObs hFix).FixedValues × ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω)) (ValuesOn Wr (swigΩ Ω)) := (M.obsCondKernel Wr (X.image SWIGNode.random ∪ (∅ : Finset (SWIGNode N))) hWr (union_subset hXr (empty_subset M.observed))).comap (fun p => (M.fixSetProj X hObs hFix p.1, M.fillZrW X hObs hFix (∅ : Finset (SWIGNode N)) p.1 p.2)) (prodMk ((M.measurable_fixSetProj X hObs hFix).comp measurable_fst) (M.measurable_fillZrW_prod X hObs hFix (∅ : Finset (SWIGNode N)))) haveI : IsSFiniteKernel zMarginalPost := by dsimp [zMarginalPost] infer_instance haveI : IsSFiniteKernel condPost := by dsimp [condPost] infer_instance have hcollapse : ((zMarginalPost ⊗ₖ condPost).map snd) sTt = condPost (sTt, (default : ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω))) := by rw [compProd_map_snd_apply] have hz : zMarginalPost sTt = dirac (default : ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω)) := by ext S hS by_cases hempty : S = ∅ · simp [hempty] · have h_univ : S = univ := by apply Set.eq_univ_of_forall intro x by_contra hx apply hempty ext y constructor · intro hy have : y = x := Subsingleton.elim y x exact elim (hx (this ▸ hy)) · intro hy simp at hy rw [h_univ] dsimp [zMarginalPost] rw [ProbabilityTheory.Kernel.map_apply _ (measurable_valuesProjection _)] rw [MeasureTheory.Measure.map_apply (measurable_valuesProjection _) MeasurableSet.univ] simp [M.obsKernel_apply_univ (M.fixSetProj X hObs hFix sTt)] rw [hz] simpa [sectR] using (MeasureTheory.Measure.dirac_bind (a := (default : ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω))) (f := condPost.sectR sTt) (hf := by fun_prop)) have hadj : M.adjustmentKernelY X hObs hFix Wr (∅ : Finset (SWIGNode N)) hWr (empty_subset _) s0 t = ((zMarginalPost ⊗ₖ condPost).map snd) sTt := by rw [SCM.adjustmentKernelY, ProbabilityTheory.Kernel.comap_apply] change M.backdoorAdjustment X hObs hFix Wr (∅ : Finset (SWIGNode N)) hWr (empty_subset _) sTt = ((zMarginalPost ⊗ₖ condPost).map snd) sTt rw [SCM.backdoorAdjustment] rw [hadj, hcollapse] have hcond : condPost (sTt, (default : ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω))) = M.obsCondKernel Wr (X.image SWIGNode.random ∪ (∅ : Finset (SWIGNode N))) hWr (union_subset hXr (empty_subset M.observed)) (s0, valuesUnionMk t (default : ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω))) := by simp [condPost, sTt, SCM.fixSetProj_fixSetExtend, SCM.fillZrW_fixSetExtend] rw [hcond] apply obsCondKernel_congr_cc M Wr (X.image SWIGNode.random ∪ (∅ : Finset (SWIGNode N))) (X.image SWIGNode.random) (union_empty _) hWr (union_subset hXr (empty_subset M.observed)) hXr exact valuesOn_heq_of_coord (union_empty _) _ _ (fun v hvU hvX => valuesUnionMk_apply_left t (default : ValuesOn (∅ : Finset (SWIGNode N)) (swigΩ Ω)) hvX)