SCM.Do.Rule2­Kernel

Kernel-level proof of do-calculus Rule 2: conditional kernels under intervention, levelset compatibility, and the rectangle-identity bridge.

Structural 2 core · 6 supporting · 2 submodules Structural helpers for Rule 2 kernels: cross-SCM compatibility and pointwise structural identities behind the kernel-level argument.
Helpers 7 core · 7 supporting This file builds the value-space maps that insert intervention values into a conditioning assignment. ★ fixSetProj_fixSetExtend★ fillZrW_fixSetExtend

Value-Space Helpers for Rule 2

This file builds the value-space maps that insert intervention values into a conditioning assignment. These maps provide the bookkeeping needed to compare conditioning on an observed random copy with conditioning on the corresponding intervention value in Rule 2.

def zFixedAsRandom reviewed
Causalean.SCM

This map reads intervention values as values of the corresponding observed random variables.

Definition (Lean source)
noncomputable def zFixedAsRandom {Z : Finset N} (z : ValuesOn (Z.image SWIGNode.fixed) (swigΩ Ω)) : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) := fun ⟨v, hv⟩ => match v, hv with | SWIGNode.random D, hv => have hD : D ∈ Z := by rcases Finset.mem_image.mp hv with ⟨D', hD', heq⟩ cases heq; exact hD' z ⟨SWIGNode.fixed D, Finset.mem_image.mpr ⟨D, hD, rfl⟩⟩ | SWIGNode.fixed _, hv => by exfalso rcases Finset.mem_image.mp hv with ⟨_, _, heq⟩ cases heq
def fillZrW reviewed
Causalean.SCM

The Rule 2 filler inserts intervention values into a conditioning assignment.

Definition (Lean source)
noncomputable def fillZrW (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) : ValuesOn W (swigΩ Ω) → ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω) := fun w => valuesUnionMk (zFixedAsRandom (valuesProjection (fixSet_image_fixed_subset M' Z hZ_obs hZ_fixed) s')) w
def valuesUnionEquiv reviewed
Causalean.SCM

A value assignment on a disjoint union is measurably equivalent to the pair of assignments on the two parts.

Definition (Lean source)
noncomputable def valuesUnionEquiv {A B : Finset (SWIGNode N)} (hDisj : Disjoint A B) : ValuesOn (A ∪ B) (swigΩ Ω) ≃ᵐ ValuesOn A (swigΩ Ω) × ValuesOn B (swigΩ Ω) where toFun ξ := (valuesProjection (subset_union_left) ξ, valuesProjection (Finset.subset_union_right) ξ) invFun p := valuesUnionMk p.1 p.2 left_inv ξ := by funext ⟨v, hv⟩ by_cases hA : v ∈ A · simp [valuesProjection, valuesUnionMk_apply_left _ _ hA] · have hB : v ∈ B := (Finset.mem_union.mp hv).resolve_left hA simp [valuesUnionMk_apply_right _ _ hv hA, valuesProjection] right_inv := by rintro ⟨a, b⟩ ext · rename_i i obtain ⟨v, hvA⟩ := i have hv : v ∈ A ∪ B := subset_union_left hvA simp [valuesProjection, valuesUnionMk_apply_left _ _ hvA] · rename_i i obtain ⟨v, hvB⟩ := i have hv : v ∈ A ∪ B := Finset.subset_union_right hvB have hA : v ∉ A := fun hA' => (Finset.disjoint_left.mp hDisj hA') hvB simp [valuesProjection, valuesUnionMk_apply_right _ _ hv hA] measurable_toFun := (measurable_valuesProjection _).prodMk (measurable_valuesProjection _) measurable_invFun := by change Measurable (fun p : ValuesOn A (swigΩ Ω) × ValuesOn B (swigΩ Ω) => valuesUnionMk p.1 p.2) refine measurable_pi_iff.mpr ?_ rintro ⟨v, hv⟩ by_cases hA : v ∈ A · have h_eq : (fun p : ValuesOn A (swigΩ Ω) × ValuesOn B (swigΩ Ω) => valuesUnionMk p.1 p.2 ⟨v, hv⟩) = (fun p => p.1 ⟨v, hA⟩) := funext fun _ => valuesUnionMk_apply_left _ _ hA rw [h_eq] exact (measurable_pi_apply _).comp measurable_fst · have hB : v ∈ B := (Finset.mem_union.mp hv).resolve_left hA have h_eq : (fun p : ValuesOn A (swigΩ Ω) × ValuesOn B (swigΩ Ω) => valuesUnionMk p.1 p.2 ⟨v, hv⟩) = (fun p => p.2 ⟨v, hB⟩) := funext fun _ => valuesUnionMk_apply_right _ _ hv hA rw [h_eq] exact (measurable_pi_apply _).comp measurable_snd
def xRandomAsFixed reviewed
Causalean.SCM

This map reads observed treatment values as values for the corresponding intervention coordinates.

Definition (Lean source)
noncomputable def xRandomAsFixed {X : Finset N} (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : ValuesOn (X.image SWIGNode.fixed) (swigΩ Ω) := fun ⟨v, hv⟩ => match v, hv with | SWIGNode.fixed D, hv => have hD : D ∈ X := by rcases Finset.mem_image.mp hv with ⟨D', hD', heq⟩; cases heq; exact hD' t ⟨SWIGNode.random D, Finset.mem_image.mpr ⟨D, hD, rfl⟩⟩ | SWIGNode.random _, hv => by exfalso; rcases Finset.mem_image.mp hv with ⟨_, _, heq⟩; cases heq
def fixSetExtend reviewed
Causalean.SCM

This map extends a base fixed-value assignment with treatment values for a post-intervention model.

Definition (Lean source)
noncomputable def fixSetExtend (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : (M.fixSet X hObs hFix).FixedValues := fun ⟨v, hv⟩ => if hM : v ∈ M.fixed then s0 ⟨v, hM⟩ else have hXf : v ∈ X.image SWIGNode.fixed := (Finset.mem_union.mp (by simpa using hv)).resolve_left hM xRandomAsFixed t ⟨v, hXf⟩
lemma fixSetProj_fixSetExtend reviewed
Causalean.SCM

For the intervention names X, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, projecting the extended post-intervention fixed assignment — built from the base assignment s0 and treatment value t — back onto the original fixed coordinates recovers s0.

Formal statement
M :
SCM N Ω
X :
hObs :
∀ D ∈ X, SWIGNode.random D ∈ M.observed
hFix :
∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed
s0 :
M.FixedValues
t :
ValuesOn (X.image SWIGNode.random) (swigΩ Ω)
M.fixSetProj X hObs hFix (M.fixSetExtend X hObs hFix s0 t) = s0
Proof (Lean source)
lemma fixSetProj_fixSetExtend (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : M.fixSetProj X hObs hFix (M.fixSetExtend X hObs hFix s0 t) = s0 := by funext ⟨v, hv⟩ simp only [fixSetProj, valuesProjection, fixSetExtend, dif_pos hv]
lemma fillZrW_fixSetExtend reviewed
Causalean.SCM

For the intervention names X, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, filling the conditioning assignment z against the extended post-intervention fixed assignment built from the base assignment s0 and treatment value t equals directly combining t and z into one assignment on their union.

Formal statement
M :
SCM N Ω
X :
hObs :
∀ D ∈ X, SWIGNode.random D ∈ M.observed
hFix :
∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed
Z :
s0 :
M.FixedValues
t :
ValuesOn (X.image SWIGNode.random) (swigΩ Ω)
z :
M.fillZrW X hObs hFix Z (M.fixSetExtend X hObs hFix s0 t) z = valuesUnionMk t z
Proof (Lean source)
lemma fillZrW_fixSetExtend (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)) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) (z : ValuesOn Z (swigΩ Ω)) : M.fillZrW X hObs hFix Z (M.fixSetExtend X hObs hFix s0 t) z = valuesUnionMk t z := by rw [SCM.fillZrW, SCM.zFixedAsRandom_proj_fixSetExtend]
7 supporting declarations (lemmas, instances)
  • measurable_zFixedAsRandom lemma — Reading intervention values as observed random-variable values is a measurable operation.
    Z :
    Measurable (zFixedAsRandom (Ω := Ω) (Z := Z))
    Proof (Lean source)
    lemma measurable_zFixedAsRandom {Z : Finset N} : Measurable (zFixedAsRandom (Ω := Ω) (Z := Z)) := by refine measurable_pi_iff.mpr ?_ rintro ⟨v, hv⟩ obtain ⟨D, hD, rfl⟩ := Finset.mem_image.mp hv -- v = SWIGNode.random D; output is `z ⟨.fixed D, _⟩` exact measurable_pi_apply _
    Causalean.SCM.measurable_zFixedAsRandom · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:67
  • measurable_fillZrW theorem — The Rule 2 filler is measurable as a function of the free conditioning assignment.
    M' :
    SCM N Ω
    Z :
    hZ_obs :
    ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
    hZ_fixed :
    ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
    W :
    s' :
    (M'.fixSet Z hZ_obs hZ_fixed).FixedValues
    Measurable (M'.fillZrW Z hZ_obs hZ_fixed W s')
    Proof (Lean source)
    theorem measurable_fillZrW (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) : Measurable (M'.fillZrW Z hZ_obs hZ_fixed W s') := by unfold fillZrW exact measurable_valuesUnionMk_right _
    Causalean.SCM.measurable_fillZrW · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:154
  • measurable_fillZrW_prod theorem — The Rule 2 filler is jointly measurable in the post-intervention fixed slice and the free conditioning coordinates.
    M' :
    SCM N Ω
    Z :
    hZ_obs :
    ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
    hZ_fixed :
    ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
    W :
    Measurable (fun p : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues × ValuesOn W (swigΩ Ω) => M'.fillZrW Z hZ_obs hZ_fixed W p.1 p.2)
    Proof (Lean source)
    theorem measurable_fillZrW_prod (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) : Measurable (fun p : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues × ValuesOn W (swigΩ Ω) => M'.fillZrW Z hZ_obs hZ_fixed W p.1 p.2) := by unfold fillZrW change Measurable ((fun q : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => valuesUnionMk q.1 q.2) ∘ (fun p : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues × ValuesOn W (swigΩ Ω) => (zFixedAsRandom (valuesProjection (fixSet_image_fixed_subset M' Z hZ_obs hZ_fixed) p.1), p.2))) refine (measurable_valuesUnionMk (Ω := swigΩ Ω) (A := Z.image SWIGNode.random) (B := W)).comp ?_ refine prodMk ?_ measurable_snd exact measurable_zFixedAsRandom.comp ((measurable_valuesProjection _).comp measurable_fst)
    Causalean.SCM.measurable_fillZrW_prod · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:167
  • measurable_xRandomAsFixed lemma — Reading observed treatment values as intervention-coordinate values is measurable.
    X :
    Measurable (xRandomAsFixed (Ω := Ω) (X := X))
    Proof (Lean source)
    lemma measurable_xRandomAsFixed {X : Finset N} : Measurable (xRandomAsFixed (Ω := Ω) (X := X)) := by refine measurable_pi_iff.mpr ?_ rintro ⟨v, hv⟩ obtain ⟨D, hD, rfl⟩ := Finset.mem_image.mp hv exact measurable_pi_apply _
    Causalean.SCM.measurable_xRandomAsFixed · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:210
  • fixSetExtend_apply_new_fixed lemma — A newly fixed coordinate in fixSetExtend reads the matching observed intervention coordinate.
    M :
    SCM N Ω
    X :
    hObs :
    ∀ D ∈ X, SWIGNode.random D ∈ M.observed
    hFix :
    ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed
    s0 :
    M.FixedValues
    t :
    ValuesOn (X.image SWIGNode.random) (swigΩ Ω)
    D :
    N
    hD :
    D ∈ X
    M.fixSetExtend X hObs hFix s0 t ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M X hObs hFix hD⟩
    = t ⟨SWIGNode.random D, Finset.mem_image.mpr ⟨D, hD, rfl⟩⟩
    Proof (Lean source)
    @[simp] lemma fixSetExtend_apply_new_fixed (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) {D : N} (hD : D ∈ X) : M.fixSetExtend X hObs hFix s0 t ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M X hObs hFix hD⟩ = t ⟨SWIGNode.random D, Finset.mem_image.mpr ⟨D, hD, rfl⟩⟩ := by simp [fixSetExtend, hFix D hD, xRandomAsFixed]
    Causalean.SCM.fixSetExtend_apply_new_fixed · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:233
  • measurable_fixSetExtend lemma — Extending a base fixed-value assignment is measurable in the treatment value when the base assignment is held fixed.
    M :
    SCM N Ω
    X :
    hObs :
    ∀ D ∈ X, SWIGNode.random D ∈ M.observed
    hFix :
    ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed
    s0 :
    M.FixedValues
    Measurable (M.fixSetExtend X hObs hFix s0)
    Proof (Lean source)
    lemma measurable_fixSetExtend (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (s0 : M.FixedValues) : Measurable (M.fixSetExtend X hObs hFix s0) := by refine measurable_pi_iff.mpr ?_ rintro ⟨v, hv⟩ by_cases hM : v ∈ M.fixed · simp only [fixSetExtend, dif_pos hM]; exact measurable_const · have hXf : v ∈ X.image SWIGNode.fixed := (Finset.mem_union.mp (by simpa using hv)).resolve_left hM have : (fun t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω) => M.fixSetExtend X hObs hFix s0 t ⟨v, hv⟩) = fun t => xRandomAsFixed t ⟨v, hXf⟩ := by funext t; simp only [fixSetExtend, dif_neg hM] rw [this] exact (measurable_xRandomAsFixed).eval
    Causalean.SCM.measurable_fixSetExtend · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:246
  • zFixedAsRandom_proj_fixSetExtend lemma — Relabeling the treatment part of the extended fixed assignment back to observed coordinates recovers the treatment assignment.
    M :
    SCM N Ω
    X :
    hObs :
    ∀ D ∈ X, SWIGNode.random D ∈ M.observed
    hFix :
    ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed
    s0 :
    M.FixedValues
    t :
    ValuesOn (X.image SWIGNode.random) (swigΩ Ω)
    SCM.zFixedAsRandom (valuesProjection (SCM.fixSet_image_fixed_subset M X hObs hFix) (M.fixSetExtend X hObs hFix s0 t))
    = t
    Proof (Lean source)
    lemma zFixedAsRandom_proj_fixSetExtend (M : SCM N Ω) (X : Finset N) (hObs : ∀ D ∈ X, SWIGNode.random D ∈ M.observed) (hFix : ∀ D ∈ X, SWIGNode.fixed D ∉ M.fixed) (s0 : M.FixedValues) (t : ValuesOn (X.image SWIGNode.random) (swigΩ Ω)) : SCM.zFixedAsRandom (valuesProjection (SCM.fixSet_image_fixed_subset M X hObs hFix) (M.fixSetExtend X hObs hFix s0 t)) = t := by funext ⟨v, hv⟩ obtain ⟨D, hD, rfl⟩ := Finset.mem_image.mp hv -- LHS unfolds: zFixedAsRandom at .random D reads the .fixed D coordinate. simp only [SCM.zFixedAsRandom, valuesProjection] -- The .fixed D coordinate of fixSetExtend: .fixed D ∉ M.fixed, so it is -- xRandomAsFixed t ⟨.fixed D, _⟩ = t ⟨.random D, _⟩. have hMf : SWIGNode.fixed D ∉ M.fixed := hFix D hD simp only [SCM.fixSetExtend, dif_neg hMf, SCM.xRandomAsFixed]
    Causalean.SCM.zFixedAsRandom_proj_fixSetExtend · Causalean/SCM/Do/Rule2Kernel/Helpers.lean:278
Discrete­ZHelpers 1 core · 2 supporting This file provides the discrete-treatment measure-theoretic helpers used to state Pearl's action-observation exchange without requiring the post-intervention treatment coordinate to be almost surely pinned. ★ obsKernel_fixSet_W_marginal_eq_M1_marginal

Discrete Treatment Helpers for Rule 2

This file provides the discrete-treatment measure-theoretic helpers used to state Pearl's action-observation exchange without requiring the post-intervention treatment coordinate to be almost surely pinned. It proves the W-marginal equality obsKernel_fixSet_W_marginal_eq_M1_marginal, the filled-assignment pullback equality mu_C_comap_F_eq_nu_C_comap_F, and the discrete conditional kernel bridge obsCondKernel_cross_eq_ae_of_discrete. Together these connect post-intervention adjustment marginals to pre-intervention joint marginals using overlap, positivity, and the non-descendance condition needed for the Rule 3 marginal step.

theorem obsKernel_fixSet_W_marginal_eq_M1_marginal reviewed
Causalean.SCM

Rule 3 W-marginal equality for Rule 2. For the intervention on names Z, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, and a conditioning set W contained in the observed variables, if no fixed copy of a name in Z is an ancestor, in the post-intervention DAG, of any node in W, then the W-marginal of the intervened model's observational kernel at a fixed assignment s equals the W-marginal of the base model's observational kernel at the corresponding projected assignment.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
W :
hW :
W ⊆ M'.observed
hWNonDesc :
∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v
s :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s).map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW))
= (M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection hW)
Proof (Lean source)
theorem obsKernel_fixSet_W_marginal_eq_M1_marginal (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (hW : W ⊆ M'.observed) (hWNonDesc : ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v) (s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) : ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s).map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) = (M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection hW) := by -- Rule 3 specialised to `T := W`: the W-marginal of the intervention -- kernel equals the W-marginal of the original kernel, because no z ∈ Z -- has `.fixed z` as ancestor of any v ∈ W in the post-intervention DAG. exact condDistrib_intervention_ancestral_eq M' Z hZ_obs hZ_fixed W hW (fun z hz v hv => hWNonDesc z hz v hv) s
2 supporting declarations (lemmas, instances)
  • mu_C_comap_F_eq_nu_C_comap_F lemma — Cross-SCM pullback equality along the filled assignment.
    M' :
    SCM N Ω
    Z :
    hZ_obs :
    ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
    hZ_fixed :
    ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
    W :
    hZrW :
    Z.image SWIGNode.random ∪ W ⊆ M'.observed
    hDisj_ZrW :
    Disjoint (Z.image SWIGNode.random) W
    MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    s :
    (M'.fixSet Z hZ_obs hZ_fixed).FixedValues
    ((M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection (Ω := swigΩ Ω) hZrW)).comap (M'.fillZrW Z hZ_obs hZ_fixed W s)
    = (((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s).map (valuesProjection (Ω := swigΩ Ω) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))).comap (M'.fillZrW Z hZ_obs hZ_fixed W s)
    Proof (Lean source)
    lemma mu_C_comap_F_eq_nu_C_comap_F (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) : ((M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection (Ω := swigΩ Ω) hZrW)).comap (M'.fillZrW Z hZ_obs hZ_fixed W s) = (((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s).map (valuesProjection (Ω := swigΩ Ω) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))).comap (M'.fillZrW Z hZ_obs hZ_fixed W s) := by classical let M2 := M'.fixSet Z hZ_obs hZ_fixed let sM1 : M'.FixedValues := M'.fixSetProj Z hZ_obs hZ_fixed s let F := M'.fillZrW Z hZ_obs hZ_fixed W s have hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW have hF_emb : MeasurableEmbedding F := measurableEmbedding_fillZrW M' Z hZ_obs hZ_fixed W hDisj_ZrW s have hπC_M1 : Measurable (valuesProjection (Ω := swigΩ Ω) hZrW : M'.ObservedValues → _) := measurable_valuesProjection _ have hπC_M2 : Measurable (valuesProjection (Ω := swigΩ Ω) hZrW_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ refine MeasureTheory.Measure.ext (fun A_W hA_W => ?_) rw [hF_emb.comap_apply, hF_emb.comap_apply] have hImg_meas : MeasurableSet (F '' A_W) := hF_emb.measurableSet_image' hA_W rw [MeasureTheory.Measure.map_apply hπC_M1 hImg_meas, MeasureTheory.Measure.map_apply hπC_M2 hImg_meas] have hBridge : M2.obsKernel s (univ ∩ (valuesProjection hZrW_M2)⁻¹' (F '' A_W)) = M'.obsKernel sM1 (univ ∩ (valuesProjection hZrW)⁻¹' (F '' A_W)) := obsKernel_inter_Wset_Zrand_levelset_eq M' Z hZ_obs hZ_fixed W hZrW hDisj_ZrW s MeasurableSet.univ hA_W rw [Set.univ_inter, Set.univ_inter] at hBridge exact hBridge.symm
    Causalean.SCM.mu_C_comap_F_eq_nu_C_comap_F · Causalean/SCM/Do/Rule2Kernel/DiscreteZHelpers.lean:113
  • obsCondKernel_cross_eq_ae_of_discrete lemma — Discrete-treatment cross-SCM conditional-kernel equality.
    M' :
    SCM N Ω
    Z :
    hZ_obs :
    ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
    hZ_fixed :
    ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
    Y W :
    hY :
    Y ⊆ M'.observed
    hW :
    W ⊆ M'.observed
    hZrW :
    Z.image SWIGNode.random ∪ W ⊆ M'.observed
    ∀ n, Nonempty (swigΩ Ω n)
    hdSep :
    (M'.fixSet Z hZ_obs hZ_fixed).dag.dSep Y (Z.image SWIGNode.random) (W ∪ (M'.fixSet Z hZ_obs hZ_fixed).fixed)
    hWNonDesc :
    ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v
    StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues
    StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues
    Nonempty (ValuesOn Y (swigΩ Ω))
    StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
    Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
    ∀ s :
    M'.FixedValues, IsFiniteMeasure (M'.obsKernel s)
    (M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s)
    (M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s)
    CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))
    MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    s :
    (M'.fixSet Z hZ_obs hZ_fixed).FixedValues
    hPositivity :
    ((M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection (Ω := swigΩ Ω) hW)) ≪ (((M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection (Ω := swigΩ Ω) hZrW)).comap (M'.fillZrW Z hZ_obs hZ_fixed W s))
    B :
    hB :
    ∀ᵐ w ∂(((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s).map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW))),
    (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B
    = ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (s, w)) B
    Proof (Lean source)
    lemma obsCondKernel_cross_eq_ae_of_discrete (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) [∀ n, StandardBorelSpace (swigΩ Ω n)] [∀ n, Nonempty (swigΩ Ω n)] (hdSep : (M'.fixSet Z hZ_obs hZ_fixed).dag.dSep Y (Z.image SWIGNode.random) (W ∪ (M'.fixSet Z hZ_obs hZ_fixed).fixed)) (hWNonDesc : ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v) [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [∀ s : M'.FixedValues, IsFiniteMeasure (M'.obsKernel s)] [∀ s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s)] [∀ s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s)] [CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) (hPositivity : ((M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection (Ω := swigΩ Ω) hW)) ≪ (((M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s)).map (valuesProjection (Ω := swigΩ Ω) hZrW)).comap (M'.fillZrW Z hZ_obs hZ_fixed W s))) {B : Set (ValuesOn Y (swigΩ Ω))} (hB : MeasurableSet B) : ∀ᵐ w ∂(((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s).map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW))), (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B = ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (s, w)) B := by classical -- Abbreviations. let M2 := M'.fixSet Z hZ_obs hZ_fixed let sM1 : M'.FixedValues := M'.fixSetProj Z hZ_obs hZ_fixed s let F := M'.fillZrW Z hZ_obs hZ_fixed W s have hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W := Disjoint.mono_right Finset.subset_union_left hdSep.2.2.1 have hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY have hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW have hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW have hF_emb : MeasurableEmbedding F := measurableEmbedding_fillZrW M' Z hZ_obs hZ_fixed W hDisj_ZrW s -- Marginal measures. let μ_C : Measure (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω)) := (M'.obsKernel sM1).map (valuesProjection hZrW) let ν_C : Measure (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω)) := (M2.obsKernel s).map (valuesProjection hZrW_M2) let μ_W : Measure (ValuesOn W (swigΩ Ω)) := (M'.obsKernel sM1).map (valuesProjection (Ω := swigΩ Ω) hW) let ν_W : Measure (ValuesOn W (swigΩ Ω)) := (M2.obsKernel s).map (valuesProjection (Ω := swigΩ Ω) hW_M2) have hμC_def : μ_C = (M'.obsKernel sM1).map (valuesProjection (Ω := swigΩ Ω) hZrW) := rfl have hνC_def : ν_C = (M2.obsKernel s).map (valuesProjection (Ω := swigΩ Ω) hZrW_M2) := rfl -- (1) Cross-SCM bridge: μ_C.comap F-a.e. w, M1.obsCondKernel(C)(sM1, F w) B -- = M2.obsCondKernel(C)(s, F w) B. have h_L2 := obsCondKernel_cross_SCM_ae_eq_on_fillZrW M' Z hZ_obs hZ_fixed Y W hY hW hZrW hDisj_ZrW s hB -- (2) D-sep collapse: ν_C-a.e. c, M2.obsCondKernel(C)(s, c) B -- = M2.obsCondKernel(W)(s, π_W^C c) B. have h_L1 := obsCondKernel_dSep_collapse_ae M' Z hZ_obs hZ_fixed Y W hY hW hdSep s hB -- (3) Pullback equality: μ_C.comap F = ν_C.comap F. have hPartA : μ_C.comap F = ν_C.comap F := mu_C_comap_F_eq_nu_C_comap_F M' Z hZ_obs hZ_fixed W hZrW hDisj_ZrW s -- (4) Rule 3 marginal equality: ν_W = μ_W as measures. have hν_W_eq_μ_W : ν_W = μ_W := by change (M2.obsKernel s).map (valuesProjection hW_M2) = (M'.obsKernel sM1).map (valuesProjection hW) exact obsKernel_fixSet_W_marginal_eq_M1_marginal M' Z hZ_obs hZ_fixed W hW hWNonDesc s -- (5) Transport h_L1 from ν_C-a.e. (in `c`) to ν_C.comap F-a.e. (in `w`, -- with `c := F w`). Step (5a): ν_C-a.e. → ν_C.restrict (range F)-a.e. have h_L1_restrict : ∀ᵐ c ∂(ν_C.restrict (range F)), (M2.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY_M2 hZrW_M2 (s, c)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)) B := MeasureTheory.ae_restrict_of_ae h_L1 -- (5b): ν_C.restrict (range F) = (ν_C.comap F).map F (`hF_emb.map_comap`). have h_map_comap_ν : (ν_C.comap F).map F = ν_C.restrict (range F) := hF_emb.map_comap ν_C rw [← h_map_comap_ν] at h_L1_restrict -- (5c): Pull back through F via MeasurableEmbedding.ae_map_iff. have h_L1_pulled : ∀ᵐ w ∂(ν_C.comap F), (M2.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY_M2 hZrW_M2 (s, F w)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) (F w))) B := (hF_emb.ae_map_iff (μ := ν_C.comap F) (p := fun c => (M2.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY_M2 hZrW_M2 (s, c)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)) B)).mp h_L1_restrict -- (6) `π_W^C (F w) = w`, by construction of F. have h_proj_F : ∀ w : ValuesOn W (swigΩ Ω), valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) (F w) = w := by intro w funext ⟨v, hvW⟩ have hv_in : v ∈ Z.image SWIGNode.random ∪ W := Finset.subset_union_right hvW have hvNotZr : v ∉ Z.image SWIGNode.random := fun hvZr => Finset.disjoint_left.mp hDisj_ZrW hvZr hvW simp only [valuesProjection, F, fillZrW] rw [valuesUnionMk_apply_right _ _ hv_in hvNotZr] -- (7) Simplify h_L1_pulled using h_proj_F. have h_L1_simpl : ∀ᵐ w ∂(ν_C.comap F), (M2.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY_M2 hZrW_M2 (s, F w)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, w)) B := by refine Filter.Eventually.mono h_L1_pulled (fun w hw => ?_) rw [h_proj_F] at hw exact hw -- (8) Combine h_L2 (μ_C.comap F-a.e.) with h_L1_simpl (ν_C.comap F-a.e.), -- using the pullback equality to identify the two measures. have h_L1_simpl_μ : ∀ᵐ w ∂(μ_C.comap F), (M2.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY_M2 hZrW_M2 (s, F w)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, w)) B := by rw [hPartA]; exact h_L1_simpl have h_chain_μ : ∀ᵐ w ∂(μ_C.comap F), (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (sM1, F w)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, w)) B := by filter_upwards [h_L2, h_L1_simpl_μ] with w hL2 hL1 exact hL2.trans hL1 -- (9) Transport from μ_C.comap F-a.e. to μ_W-a.e. via hPositivity. have h_chain_μW : ∀ᵐ w ∂μ_W, (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (sM1, F w)) B = (M2.obsCondKernel Y W hY_M2 hW_M2 (s, w)) B := hPositivity.ae_eq h_chain_μ -- (10) Rewrite the goal's measure ν_W to μ_W via the Rule 3 marginal equality. change ∀ᵐ w ∂ν_W, _ rw [hν_W_eq_μ_W] exact h_chain_μW
    Causalean.SCM.obsCondKernel_cross_eq_ae_of_discrete · Causalean/SCM/Do/Rule2Kernel/DiscreteZHelpers.lean:176
Inter­Singleton 1 core · 2 supporting This file proves that, on the event where the treatment and adjustment coordinates take the fixed value inserted by the intervention, the post-intervention observational kernel and the original observational kernel assig ★ obsKernel_inter_Wset_Zrand_levelset_eq

Level-Set Agreement for Rule 2

This file proves that, on the event where the treatment and adjustment coordinates take the fixed value inserted by the intervention, the post-intervention observational kernel and the original observational kernel assign the same mass to every additional measurable observed event. This level-set identity is the cross-model cylinder equality used in the disintegration argument for Rule 2.

theorem obsKernel_inter_Wset_Zrand_levelset_eq reviewed
Causalean.SCM

For the intervention on names Z, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, with the union of the random copies of Z and a conditioning set W contained in the observed variables and the random copies of Z disjoint from W, fix an intervened fixed assignment s'; for measurable subsets S of the observed-value space and measurable subsets A of the values on W, the intervened model's observational kernel at s', evaluated on S intersected with the preimage under the Z.random ∪ W-projection of the image of A under the filled-assignment map, equals the base model's observational kernel at the projected fixed assignment, evaluated on the analogous set.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
W :
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_ZrW :
Disjoint (Z.image SWIGNode.random) W
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s' :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
S :
Set M'.ObservedValues
A :
hS :
hA :
(M'.fixSet Z hZ_obs hZ_fixed).obsKernel s' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A))
= M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s') (S ∩ (valuesProjection hZrW)⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A))
Proof (Lean source)
theorem obsKernel_inter_Wset_Zrand_levelset_eq (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) {S : Set M'.ObservedValues} {A : Set (ValuesOn W (swigΩ Ω))} (hS : MeasurableSet S) (hA : MeasurableSet A) : (M'.fixSet Z hZ_obs hZ_fixed).obsKernel s' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)) = M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s') (S ∩ (valuesProjection hZrW)⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)) := by classical -- Abbreviations. let M1 := M' let M2 := M1.fixSet Z hZ_obs hZ_fixed have hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M1 Z hZ_obs hZ_fixed).symm ▸ hZrW let s_M1 : M1.FixedValues := M1.fixSetProj Z hZ_obs hZ_fixed s' let F := M'.fillZrW Z hZ_obs hZ_fixed W s' -- Measurability bookkeeping for the image preimage. have hF_meas : Measurable F := M'.measurable_fillZrW Z hZ_obs hZ_fixed W s' -- The image `F '' A` has the explicit form -- `{c | π_W^C c ∈ A ∧ π_Zr^C c = ζ_s}` -- which is measurable. Use this to deduce the cylinder -- `π_C⁻¹ (F '' A)` is measurable. have hπ_M1 : Measurable (valuesProjection hZrW : M1.ObservedValues → _) := measurable_valuesProjection _ have hπ_M2 : Measurable (valuesProjection hZrW_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ -- Helper: the Zr-singleton `{ζ_s}` is measurable in -- `ValuesOn (Z.image .random) (swigΩ Ω)` provided we have a witness -- `w₀ : ValuesOn W (swigΩ Ω)`. We isolate this as a parameterized lemma. -- The proof: pull back the measurable singleton -- `{valuesUnionMk ζ_s w₀} ⊆ ValuesOn (Zr ∪ W) (swigΩ Ω)` (which is -- measurable by the MSC hypothesis) under the measurable embedding -- `ζ ↦ valuesUnionMk ζ w₀`. let ζ_s : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) := zFixedAsRandom (valuesProjection (fixSet_image_fixed_subset M' Z hZ_obs hZ_fixed) s') have hSingZr : ∀ (w₀ : ValuesOn W (swigΩ Ω)), MeasurableSet ({ζ_s} : Set (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))) := by intro w₀ have hmeas : Measurable (fun ζ : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) => valuesUnionMk ζ w₀) := by refine measurable_pi_iff.mpr ?_ rintro ⟨v, hv⟩ by_cases hvZ : v ∈ Z.image SWIGNode.random · have h_eq : (fun ζ : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) => valuesUnionMk ζ w₀ ⟨v, hv⟩) = (fun ζ => ζ ⟨v, hvZ⟩) := funext fun _ => valuesUnionMk_apply_left _ _ hvZ rw [h_eq] exact measurable_pi_apply _ · have hvW : v ∈ W := (Finset.mem_union.mp hv).resolve_left hvZ have h_eq : (fun ζ : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) => valuesUnionMk ζ w₀ ⟨v, hv⟩) = (fun _ => w₀ ⟨v, hvW⟩) := funext fun _ => valuesUnionMk_apply_right _ _ hv hvZ rw [h_eq] exact measurable_const have h_pre : ({ζ_s} : Set (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))) = (fun ζ => valuesUnionMk ζ w₀)⁻¹' ({valuesUnionMk ζ_s w₀} : Set (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))) := by ext ζ simp only [Set.mem_singleton_iff, Set.mem_preimage] refine ⟨fun h => by rw [h], fun h => ?_⟩ funext ⟨v, hv⟩ have hv_union : v ∈ Z.image SWIGNode.random ∪ W := subset_union_left hv have h_coord := congrFun h ⟨v, hv_union⟩ rw [valuesUnionMk_apply_left _ _ hv, valuesUnionMk_apply_left _ _ hv] at h_coord exact h_coord rw [h_pre] exact hmeas (measurableSet_singleton _) -- Helper: prove `MeasurableSet ((valuesProjection h)⁻¹' (F '' A))` via the -- `hImg` decomposition. The proof is identical for `h = hZrW` (M1 side) -- and `h = hZrW_M2` (M2 side); we factor it. have hPreImage_meas_gen : ∀ {O : Finset (SWIGNode N)} (h : Z.image SWIGNode.random ∪ W ⊆ O) (hπ : Measurable (valuesProjection h : ValuesOn O (swigΩ Ω) → _)), MeasurableSet ((valuesProjection h)⁻¹' (F '' A)) := by intro O h hπ by_cases hW : Nonempty (ValuesOn W (swigΩ Ω)) · obtain ⟨w₀⟩ := hW have hImg : (F '' A : Set _) = (fun c : ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω) => valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random)) c)⁻¹' A ∩ (fun c => valuesProjection (subset_union_left (s₂ := W)) c)⁻¹' ({ζ_s} : Set (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))) := by ext c constructor · rintro ⟨w, hwA, rfl⟩ refine ⟨?_, ?_⟩ · simp only [Set.mem_preimage] show valuesProjection (Finset.subset_union_right) (F w) ∈ A have : valuesProjection (Finset.subset_union_right : W ⊆ _) (F w) = w := by funext ⟨v, hv⟩ simp only [valuesProjection, F, fillZrW] by_cases hvA : v ∈ Z.image SWIGNode.random · exfalso exact Finset.disjoint_left.mp hDisj_ZrW hvA hv · rw [valuesUnionMk_apply_right _ _ _ hvA] rw [this] exact hwA · simp only [Set.mem_preimage, Set.mem_singleton_iff] show valuesProjection (subset_union_left) (F w) = ζ_s funext ⟨v, hv⟩ simp only [valuesProjection, F, fillZrW] rw [valuesUnionMk_apply_left _ _ hv] · rintro ⟨hW_mem, hZr_mem⟩ simp only [Set.mem_preimage] at hW_mem simp only [Set.mem_preimage, Set.mem_singleton_iff] at hZr_mem refine ⟨valuesProjection (Finset.subset_union_right : W ⊆ _) c, hW_mem, ?_⟩ funext ⟨v, hv⟩ simp only [F, fillZrW] rcases Finset.mem_union.mp hv with hZrV | hWV · rw [valuesUnionMk_apply_left _ _ hZrV] have := congrFun hZr_mem ⟨v, hZrV⟩ simp only [valuesProjection] at this exact this.symm · by_cases hZrV' : v ∈ Z.image SWIGNode.random · rw [valuesUnionMk_apply_left _ _ hZrV'] have := congrFun hZr_mem ⟨v, hZrV'⟩ simp only [valuesProjection] at this exact this.symm · rw [valuesUnionMk_apply_right _ _ _ hZrV'] simp only [valuesProjection] rw [hImg, Set.preimage_inter] refine (hπ ((measurable_valuesProjection _) hA)).inter ?_ exact hπ ((measurable_valuesProjection _) (hSingZr w₀)) · -- `ValuesOn W` is empty. Then `A : Set (ValuesOn W)` must be `∅`, -- hence `F '' A = ∅` and the preimage is empty (measurable). have hA_empty : A = ∅ := by ext w exact ⟨fun _ => (hW ⟨w⟩).elim, fun h => h.elim⟩ rw [hA_empty, Set.image_empty, Set.preimage_empty] exact MeasurableSet.empty have hPreImage_meas_M1 : MeasurableSet ((valuesProjection hZrW)⁻¹' (F '' A)) := hPreImage_meas_gen hZrW hπ_M1 have hPreImage_meas_M2 : MeasurableSet ((valuesProjection hZrW_M2)⁻¹' (F '' A)) := hPreImage_meas_gen hZrW_M2 hπ_M2 -- LHS: unfold obsKernel → jointKernel → latentProduct.map evalMap. unfold obsKernel have hI_M2_exp : MeasurableSet (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)) := hS.inter hPreImage_meas_M2 have hI_M1_exp : MeasurableSet (S ∩ (valuesProjection hZrW)⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)) := hS.inter hPreImage_meas_M1 rw [ProbabilityTheory.Kernel.map_apply _ ((M'.fixSet Z hZ_obs hZ_fixed).measurable_randomToObserved), ProbabilityTheory.Kernel.map_apply _ M'.measurable_randomToObserved] have hmap_M2 : (map (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s')) (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)) = ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s') ((M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ⁻¹' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A))) := MeasureTheory.Measure.map_apply ((M'.fixSet Z hZ_obs hZ_fixed).measurable_randomToObserved) hI_M2_exp have hmap_M1 : (map M'.randomToObserved (M'.jointKernel (M'.fixSetProj Z hZ_obs hZ_fixed s'))) (S ∩ (valuesProjection hZrW)⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)) = (M'.jointKernel (M'.fixSetProj Z hZ_obs hZ_fixed s')) (M'.randomToObserved ⁻¹' (S ∩ (valuesProjection hZrW)⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A))) := MeasureTheory.Measure.map_apply M'.measurable_randomToObserved hI_M1_exp rw [hmap_M2, hmap_M1, jointKernel_apply_eq (M'.fixSet Z hZ_obs hZ_fixed) s', jointKernel_apply_eq M' (M'.fixSetProj Z hZ_obs hZ_fixed s')] have hf_M2_exp : Measurable (fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ) := (M'.fixSet Z hZ_obs hZ_fixed).evalMap_measurable.comp (prodMk measurable_const measurable_id) have hf_M1_exp : Measurable (fun ℓ : M'.LatentValues => M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') ℓ) := M'.evalMap_measurable.comp (prodMk measurable_const measurable_id) have hRTO_2 : Measurable (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved := (M'.fixSet Z hZ_obs hZ_fixed).measurable_randomToObserved have hRTO_1 : Measurable M'.randomToObserved := M'.measurable_randomToObserved have hpre_M2 : MeasurableSet ((M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ⁻¹' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A))) := hRTO_2 hI_M2_exp have hpre_M1 : MeasurableSet (M'.randomToObserved ⁻¹' -- … truncated; follow the source link for the rest …
2 supporting declarations (lemmas, instances)
  • obsKernel_inter_singleton_Zrand_eq theorem — Joint kernel agreement on the Z.random-level-set event.
    M' :
    SCM N Ω
    Z :
    hZ_obs :
    ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
    hZ_fixed :
    ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
    W :
    hZrW :
    Z.image SWIGNode.random ∪ W ⊆ M'.observed
    MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    s' :
    (M'.fixSet Z hZ_obs hZ_fixed).FixedValues
    w :
    S :
    Set M'.ObservedValues
    hS :
    (M'.fixSet Z hZ_obs hZ_fixed).obsKernel s' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})
    = M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s') (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})
    Proof (Lean source)
    theorem obsKernel_inter_singleton_Zrand_eq (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) (w : ValuesOn W (swigΩ Ω)) {S : Set M'.ObservedValues} (hS : MeasurableSet S) : (M'.fixSet Z hZ_obs hZ_fixed).obsKernel s' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}) = M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s') (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}) := by classical -- Abbreviations (via `let`; avoid `set` to prevent elaboration surprises). let M1 := M' let M2 := M1.fixSet Z hZ_obs hZ_fixed -- Use the explicit `.symm ▸` cast so the form matches the goal. have hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M1 Z hZ_obs hZ_fixed).symm ▸ hZrW let s_M1 : M1.FixedValues := M1.fixSetProj Z hZ_obs hZ_fixed s' let c := M'.fillZrW Z hZ_obs hZ_fixed W s' w -- Measurability bookkeeping. have h_sing : MeasurableSet ({c} : Set _) := measurableSet_singleton _ have hπ_M1 : Measurable (valuesProjection hZrW : M1.ObservedValues → _) := measurable_valuesProjection _ have hπ_M2 : Measurable (valuesProjection hZrW_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ have h_pre_M1 : MeasurableSet ((valuesProjection hZrW)⁻¹' {c}) := hπ_M1 h_sing have h_pre_M2 : MeasurableSet ((valuesProjection hZrW_M2)⁻¹' {c}) := hπ_M2 h_sing have hI_M1 : MeasurableSet (S ∩ (valuesProjection hZrW)⁻¹' {c}) := hS.inter h_pre_M1 have hI_M2 : MeasurableSet (S ∩ (valuesProjection hZrW_M2)⁻¹' {c}) := hS.inter h_pre_M2 have hRTO_M2 : Measurable M2.randomToObserved := M2.measurable_randomToObserved have hRTO_M1 : Measurable M1.randomToObserved := M1.measurable_randomToObserved have hf_M1 : Measurable (fun ℓ : M1.LatentValues => M1.evalMap s_M1 ℓ) := M1.evalMap_measurable.comp (prodMk measurable_const measurable_id) have hf_M2 : Measurable (fun ℓ : M2.LatentValues => M2.evalMap s' ℓ) := M2.evalMap_measurable.comp (prodMk measurable_const measurable_id) have hcast : Measurable (valuesProjection (le_of_eq (fixSet_unobserved M1 Z hZ_obs hZ_fixed).symm) : M2.LatentValues → M1.LatentValues) := measurable_valuesProjection _ -- LHS: unfold obsKerneljointKernel → latentProduct.map evalMap. unfold obsKernel rw [ProbabilityTheory.Kernel.map_apply _ ((M'.fixSet Z hZ_obs hZ_fixed).measurable_randomToObserved), ProbabilityTheory.Kernel.map_apply _ M'.measurable_randomToObserved] have hI_M2_exp : MeasurableSet (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}) := by exact hS.inter ((measurable_valuesProjection _) (measurableSet_singleton _)) have hI_M1_exp : MeasurableSet (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}) := by exact hS.inter ((measurable_valuesProjection _) (measurableSet_singleton _)) have hmap_M2 : (map (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s')) (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}) = ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s') ((M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ⁻¹' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})) := by exact MeasureTheory.Measure.map_apply ((M'.fixSet Z hZ_obs hZ_fixed).measurable_randomToObserved) hI_M2_exp have hmap_M1 : (map M'.randomToObserved (M'.jointKernel (M'.fixSetProj Z hZ_obs hZ_fixed s'))) (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}) = (M'.jointKernel (M'.fixSetProj Z hZ_obs hZ_fixed s')) (M'.randomToObserved ⁻¹' (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})) := by exact MeasureTheory.Measure.map_apply M'.measurable_randomToObserved hI_M1_exp rw [hmap_M2, hmap_M1, jointKernel_apply_eq (M'.fixSet Z hZ_obs hZ_fixed) s', jointKernel_apply_eq M' (M'.fixSetProj Z hZ_obs hZ_fixed s')] have hf_M2_exp : Measurable (fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ) := by exact (M'.fixSet Z hZ_obs hZ_fixed).evalMap_measurable.comp (prodMk measurable_const measurable_id) have hf_M1_exp : Measurable (fun ℓ : M'.LatentValues => M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') ℓ) := by exact M'.evalMap_measurable.comp (prodMk measurable_const measurable_id) have hpre_M2 : MeasurableSet ((M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ⁻¹' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})) := (M'.fixSet Z hZ_obs hZ_fixed).measurable_randomToObserved hI_M2_exp have hpre_M1 : MeasurableSet (M'.randomToObserved ⁻¹' (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})) := M'.measurable_randomToObserved hI_M1_exp have heval_M2 : (map (fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ) (M'.fixSet Z hZ_obs hZ_fixed).latentProduct) ((M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ⁻¹' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})) = (M'.fixSet Z hZ_obs hZ_fixed).latentProduct ((fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ) ⁻¹' ((M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ⁻¹' (S ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW))⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}))) := by exact MeasureTheory.Measure.map_apply hf_M2_exp hpre_M2 have heval_M1 : (map (fun ℓ : M'.LatentValues => M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') ℓ) M'.latentProduct) (M'.randomToObserved ⁻¹' (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w})) = M'.latentProduct ((fun ℓ : M'.LatentValues => M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') ℓ) ⁻¹' (M'.randomToObserved ⁻¹' (S ∩ (valuesProjection hZrW)⁻¹' {M'.fillZrW Z hZ_obs hZ_fixed W s' w}))) := by exact MeasureTheory.Measure.map_apply hf_M1_exp hpre_M1 rw [heval_M2, heval_M1, ← fixSet_latentProduct_compat M' Z hZ_obs hZ_fixed, MeasureTheory.Measure.map_apply (measurable_valuesProjection _) (hf_M1_exp hpre_M1)] -- Goal: M2.latentProduct {ℓ : rando(M2.evalMap s' ℓ) ∈ I} = M2.latentProduct {ℓ : ...}. -- Reduce to set equality on the same M2.latentProduct. congr 1 -- Two preimage sets (in M2.LatentValues): -- L2 := {ℓ : rando(M2.evalMap s' ℓ) ∈ S ∩ π_C⁻¹{c}} -- L1 := {ℓ : cast ℓ ∈ {ℓ_M1 : rando(M1.evalMap s_M1 ℓ_M1) ∈ S ∩ π_C⁻¹{c}}} -- = {ℓ : rando(M1.evalMap s_M1 (cast ℓ)) ∈ S ∩ π_C⁻¹{c}} apply Set.eq_of_subset_of_subset all_goals intro ℓ hℓ simp only [Set.mem_preimage, Set.mem_inter_iff] at hℓ ⊢ -- Both directions use the same core mechanism: on the preimage, one side's -- evalMap is on the Z-level set; bridge via Claim A/B to get pointwise -- agreement of rando(evalMap) at every observed, hence the other side -- inherits membership. · -- ⊆: LHS (M2-side) ⊆ RHS (M1-side via cast). rcases hℓ with ⟨hS_mem, hπ_mem⟩ -- Extract LS_M2 from π_C = c. have hLS_M2 : ∀ D (hD : D ∈ Z), M2.evalMap s' ℓ ⟨SWIGNode.random D, mem_union_left _ (hZ_obs D hD)⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hD⟩ := by intro D hD -- π_C(rando(M2.evalMap s' ℓ)) = c at ⟨.random D, _⟩. have hD_in : SWIGNode.random D ∈ Z.image SWIGNode.random ∪ W := mem_union_left _ (Finset.mem_image.mpr ⟨D, hD, rfl⟩) have hcoord := congrFun hπ_mem ⟨SWIGNode.random D, hD_in⟩ have hc_at : c ⟨SWIGNode.random D, hD_in⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hD⟩ := by show (valuesUnionMk (zFixedAsRandom (valuesProjection (fixSet_image_fixed_subset M' Z hZ_obs hZ_fixed) s')) w) ⟨SWIGNode.random D, hD_in⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hD⟩ rw [valuesUnionMk_apply_left _ _ (Finset.mem_image.mpr ⟨D, hD, rfl⟩)] rfl exact hcoord.trans hc_at -- Apply the M2-direction level-set bridge at each observed v. refine ⟨?_, ?_⟩ · -- S membership: rando(M1.evalMap s_M1 (cast ℓ)) ∈ S. have heq : M1.randomToObserved (M1.evalMap s_M1 (valuesProjection (le_of_eq (fixSet_unobserved M1 Z hZ_obs hZ_fixed).symm) ℓ)) = M2.randomToObserved (M2.evalMap s' ℓ) := by funext v simp only [randomToObserved] exact (fixSet_evalMap_levelset_compat_M2 M' Z hZ_obs hZ_fixed s' ℓ hLS_M2 v.property).symm rw [heq] exact hS_mem · -- π_C membership: preserved under the same pointwise equality. have heq : M1.randomToObserved (M1.evalMap s_M1 (valuesProjection (le_of_eq (fixSet_unobserved M1 Z hZ_obs hZ_fixed).symm) ℓ)) = M2.randomToObserved (M2.evalMap s' ℓ) := by funext v simp only [randomToObserved] exact (fixSet_evalMap_levelset_compat_M2 M' Z hZ_obs hZ_fixed s' ℓ hLS_M2 v.property).symm rw [heq] exact hπ_mem · -- ⊇: RHS (M1-side via cast) ⊆ LHS (M2-side). rcases hℓ with ⟨hS_mem, hπ_mem⟩ -- Extract LS_M1(cast ℓ) from π_C = c. have hLS_M1 : ∀ D (hD : D ∈ Z), M1.evalMap s_M1 (valuesProjection (le_of_eq (fixSet_unobserved M1 Z hZ_obs hZ_fixed).symm) ℓ) ⟨SWIGNode.random D, mem_union_left _ (hZ_obs D hD)⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hD⟩ := by intro D hD have hD_in : SWIGNode.random D ∈ Z.image SWIGNode.random ∪ W := mem_union_left _ (Finset.mem_image.mpr ⟨D, hD, rfl⟩) have hcoord := congrFun hπ_mem ⟨SWIGNode.random D, hD_in⟩ have hc_at : c ⟨SWIGNode.random D, hD_in⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hD⟩ := by show (valuesUnionMk (zFixedAsRandom -- … truncated; follow the source link for the rest …
    Causalean.SCM.obsKernel_inter_singleton_Zrand_eq · Causalean/SCM/Do/Rule2Kernel/InterSingleton.lean:39
  • obsKernel_disintegrate_rect theorem — Base-model disintegration over condition coordinates.
    M :
    SCM N Ω
    Y CC :
    hY :
    Y ⊆ M.observed
    hCC :
    CC ⊆ M.observed
    Nonempty (ValuesOn Y (swigΩ Ω))
    s :
    M.FixedValues
    D :
    Set (ValuesOn CC (swigΩ Ω))
    B :
    hD :
    hB :
    M.obsKernel s ((valuesProjection hCC)⁻¹' D ∩ (valuesProjection hY)⁻¹' B)
    = ∫⁻ c in D, M.obsCondKernel Y CC hY hCC (s, c) B ∂((M.obsKernel s).map (valuesProjection hCC))
    Proof (Lean source)
    theorem obsKernel_disintegrate_rect (M : SCM N Ω) (Y CC : Finset (SWIGNode N)) (hY : Y ⊆ M.observed) (hCC : CC ⊆ M.observed) [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [CountableOrCountablyGenerated M.FixedValues (ValuesOn CC (swigΩ Ω))] (s : M.FixedValues) {D : Set (ValuesOn CC (swigΩ Ω))} {B : Set (ValuesOn Y (swigΩ Ω))} (hD : MeasurableSet D) (hB : MeasurableSet B) : M.obsKernel s ((valuesProjection hCC)⁻¹' D ∩ (valuesProjection hY)⁻¹' B) = ∫⁻ c in D, M.obsCondKernel Y CC hY hCC (s, c) B ∂((M.obsKernel s).map (valuesProjection hCC)) := by classical have hπCC : Measurable (valuesProjection (Ω := swigΩ Ω) hCC) := measurable_valuesProjection _ have hπY : Measurable (valuesProjection (Ω := swigΩ Ω) hY) := measurable_valuesProjection _ -- κ := obsCondPairKernel. set κ : Kernel M.FixedValues (ValuesOn CC (swigΩ Ω) × ValuesOn Y (swigΩ Ω)) := M.obsCondPairKernel Y CC hY hCC with hκ_def haveI hMarkov_κ : IsMarkovKernel κ := by rw [hκ_def] unfold obsCondPairKernel exact ProbabilityTheory.Kernel.IsMarkovKernel.map _ (hπCC.prodMk hπY) haveI : IsFiniteKernel κ := inferInstance -- Step 1: κ s (D ×ˢ B) = obsKernel cylinder. have h_pre : (valuesProjection hCC)⁻¹' D ∩ (valuesProjection hY)⁻¹' B = (fun ω => (valuesProjection hCC ω, valuesProjection hY ω))⁻¹' (D ×ˢ B) := by ext ω; simp [Set.mem_inter_iff, Set.mem_preimage, Set.mem_prod] have hKpair : κ s (D ×ˢ B) = M.obsKernel s ((valuesProjection hCC)⁻¹' D ∩ (valuesProjection hY)⁻¹' B) := by rw [hκ_def]; unfold obsCondPairKernel rw [ProbabilityTheory.Kernel.map_apply' _ (hπCC.prodMk hπY) _ (hD.prod hB)] rw [h_pre] -- Step 2: Kernel.fst κ s = (M.obsKernel s).map (valuesProjection hCC). have hfst : ProbabilityTheory.Kernel.fst κ s = (M.obsKernel s).map (valuesProjection hCC) := by rw [hκ_def] unfold obsCondPairKernel rw [ProbabilityTheory.Kernel.fst_map_prod _ hπY, ProbabilityTheory.Kernel.map_apply _ hπCC] -- Step 3: Mathlib disintegration for κ. have hKey : ∫⁻ c in D, ProbabilityTheory.Kernel.condKernel κ (s, c) B ∂(ProbabilityTheory.Kernel.fst κ s) = κ s (D ×ˢ B) := ProbabilityTheory.setLIntegral_condKernel_eq_measure_prod (κ := κ) s hD hB -- Step 4: obsCondKernel = condKernel of κ (definitional, up to instance). -- Assemble (sidestep instance rewriting by going through ENNReal eq). rw [← hKpair, ← hKey, hfst] -- Goal: ∫⁻ c in D, condKernel κ (s,c) B d(map π_CC obsKernel s) -- = ∫⁻ c in D, obsCondKernel Y CC … (s,c) B d(map π_CC obsKernel s) refine MeasureTheory.lintegral_congr_ae ?_ refine Filter.Eventually.of_forall ?_ intro c -- obsCondKernel is defined as condKernel of obsCondPairKernel. change ProbabilityTheory.Kernel.condKernel κ (s, c) B = M.obsCondKernel Y CC hY hCC (s, c) B rfl
    Causalean.SCM.obsKernel_disintegrate_rect · Causalean/SCM/Do/Rule2Kernel/InterSingleton.lean:693
Levelset­Compat 2 core · 0 supporting This file proves that the evaluation maps of the single-intervention and double-intervention models agree on the latent level set where the single intervention already realizes the additional treatment values. ★ fixSet_evalMap_levelset_compat★ fixSet_evalMap_levelset_compat_M2

Rule 2 Level-Set Compatibility

This file proves that the evaluation maps of the single-intervention and double-intervention models agree on the latent level set where the single intervention already realizes the additional treatment values. This is the evaluation-map bridge used in the kernel proof of Rule 2 of do-calculus.

theorem fixSet_evalMap_levelset_compat reviewed
Causalean.SCM

Cross-SCM evalMap level-set bridge for Rule 2. For the intervention on names Z, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, fix an intervened fixed assignment s' and a latent draw . Suppose on the "level set" picked out by , the base model's evaluation map at the projected fixed assignment already reproduces, at every random copy of a name in Z, the intervention value recorded in s'; then at any observed node v in the intervened model, the intervened model's evaluation map at (s', ℓ) agrees with the base model's evaluation map at the projected fixed assignment and the correspondingly reindexed latent draw.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
s' :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
:
(M'.fixSet Z hZ_obs hZ_fixed).LatentValues
hLevelSet :
∀ D (hD : D ∈ Z),
M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') (valuesProjection (le_of_eq (fixSet_unobserved M' Z hZ_obs hZ_fixed).symm) ℓ) ⟨SWIGNode.random D, mem_union_left _ (hZ_obs D hD)⟩
= s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩
v :
hv :
v ∈ (M'.fixSet Z hZ_obs hZ_fixed).observed
(M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ ⟨v, mem_union_left _ hv⟩
= M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') (valuesProjection (le_of_eq (fixSet_unobserved M' Z hZ_obs hZ_fixed).symm) ℓ) ⟨v, mem_union_left _ (le_of_eq (fixSet_observed M' Z hZ_obs hZ_fixed) hv)⟩
Proof (Lean source)
theorem fixSet_evalMap_levelset_compat (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) (ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues) (hLevelSet : ∀ D (hD : D ∈ Z), M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') (valuesProjection (le_of_eq (fixSet_unobserved M' Z hZ_obs hZ_fixed).symm) ℓ) ⟨SWIGNode.random D, mem_union_left _ (hZ_obs D hD)⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩) {v : SWIGNode N} (hv : v ∈ (M'.fixSet Z hZ_obs hZ_fixed).observed) : (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ ⟨v, mem_union_left _ hv⟩ = M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') (valuesProjection (le_of_eq (fixSet_unobserved M' Z hZ_obs hZ_fixed).symm) ℓ) ⟨v, mem_union_left _ (le_of_eq (fixSet_observed M' Z hZ_obs hZ_fixed) hv)⟩ := by classical let M1 := M' let M2 := M1.fixSet Z hZ_obs hZ_fixed have h_obs_eq : M2.observed = M1.observed := rfl have h_unobs : M2.unobserved = M1.unobserved := rfl let s_M1 : M1.FixedValues := M1.fixSetProj Z hZ_obs hZ_fixed s' let ℓ_M1 : M1.LatentValues := valuesProjection (le_of_eq h_unobs.symm) ℓ -- Strong recursion on `M2.observedIndex ⟨v, hv⟩`. suffices h_obs : ∀ (n : ℕ) (w : SWIGNode N) (hw : w ∈ M2.observed), (M2.observedIndex ⟨w, hw⟩).val = n → M2.evalMap s' ℓ ⟨w, mem_union_left _ hw⟩ = M1.evalMap s_M1 ℓ_M1 ⟨w, mem_union_left _ hw⟩ by exact h_obs _ v hv rfl intro n induction n using Nat.strongRecOn with | _ n ih => intro v hv hidx have hv_M1 : v ∈ M1.observed := hv rw [SCM.evalMap_observed_unfold M2 s' ℓ ⟨v, hv⟩, SCM.evalMap_observed_unfold M1 s_M1 ℓ_M1 ⟨v, hv_M1⟩] -- Unfold `M2.structFun ⟨v, _⟩` to `M1.structFun ⟨v, _⟩ ∘ fixMonoParentMap`. change M1.structFun ⟨v, hv_M1⟩ (fixMonoParentMap M1.toSWIGGraph Z hZ_obs hZ_fixed v (fun w : {w // w ∈ (M1.splitMono Z hZ_obs hZ_fixed).dag.parents v} => if huo : w.val ∈ M2.unobserved then ℓ ⟨w.val, huo⟩ else if hfix : w.val ∈ M2.fixed then s' ⟨w.val, hfix⟩ else have hedge : M2.dag.edge w.val v := M2.dag.mem_parents.mp w.property have hobs : w.val ∈ M2.observed := by rcases Finset.mem_union.mp (M2.dag_edges_classified _ _ hedge).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix · exact hob · exact absurd h2 huo M2.evalMap s' ℓ ⟨w.val, mem_union_left _ hobs⟩)) = M1.structFun ⟨v, hv_M1⟩ (fun w : {w // w ∈ M1.dag.parents v} => if huo : w.val ∈ M1.unobserved then ℓ_M1 ⟨w.val, huo⟩ else if hfix : w.val ∈ M1.fixed then s_M1 ⟨w.val, hfix⟩ else have hedge : M1.dag.edge w.val v := M1.dag.mem_parents.mp w.property have hobs : w.val ∈ M1.observed := by rcases Finset.mem_union.mp (M1.dag_edges_classified _ _ hedge).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix · exact hob · exact absurd h2 huo M1.evalMap s_M1 ℓ_M1 ⟨w.val, mem_union_left _ hobs⟩) congr 1 funext w rcases w with ⟨wVal, hwVal_M1⟩ cases wVal with | random u => by_cases hu_Z : u ∈ Z · -- **New case for Rule 2**: u ∈ Z. LHS reads M2-tuple at `.fixed u` -- (via `fixMonoParentMap_apply_random` since Z is the split target). rw [fixMonoParentMap_apply_random M1.toSWIGGraph Z hZ_obs hZ_fixed v u hu_Z _ hwVal_M1] -- LHS evaluation at `.fixed u`: not unobserved (.fixed nodes are fixed), -- is in M2.fixed via Z.image .fixed. have huo_M2 : (SWIGNode.fixed u : SWIGNode N) ∉ M2.unobserved := by intro h rcases M2.unobserved_is_random _ h with ⟨_, hEq⟩; cases hEq have hfix_M2 : (SWIGNode.fixed u : SWIGNode N) ∈ M2.fixed := SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hu_Z simp only [dif_neg huo_M2, dif_pos hfix_M2] -- RHS evaluation at `.random u`: observed, so falls through to -- a recursive M1.evalMap call. Use the level-set hypothesis. have hobs_M1 : (SWIGNode.random u : SWIGNode N) ∈ M1.observed := hZ_obs u hu_Z have huo_M1 : (SWIGNode.random u : SWIGNode N) ∉ M1.unobserved := Finset.disjoint_left.mp M1.obs_unobs_disjoint hobs_M1 have hfix_M1 : (SWIGNode.random u : SWIGNode N) ∉ M1.fixed := by intro h rcases M1.fixed_is_fixed _ h with ⟨_, hEq⟩; cases hEq simp only [dif_neg huo_M1, dif_neg hfix_M1] -- RHS = M1.evalMap s_M1 ℓ_M1 ⟨.random u, _⟩ = s' ⟨.fixed u, _⟩ -- by the level-set hypothesis. exact (hLevelSet u hu_Z).symm · -- **Old case (Rule 3 mirror)**: u ∉ Z. fixMonoParentMap acts -- identity-like at `.random u`. rw [fixMonoParentMap_apply_random_notMem M1.toSWIGGraph Z hZ_obs hZ_fixed v _ u hu_Z hwVal_M1] by_cases huo : (SWIGNode.random u : SWIGNode N) ∈ M1.unobserved · have huo_M2 : SWIGNode.random u ∈ M2.unobserved := huo simp only [dif_pos huo, dif_pos huo_M2] rfl · have huo_M2 : SWIGNode.random u ∉ M2.unobserved := huo simp only [dif_neg huo, dif_neg huo_M2] by_cases hfix : (SWIGNode.random u : SWIGNode N) ∈ M1.fixed · exfalso rcases M1.fixed_is_fixed _ hfix with ⟨_, hfix_eq⟩; cases hfix_eq · have hfix_M2 : (SWIGNode.random u : SWIGNode N) ∉ M2.fixed := by intro h have : (SWIGNode.random u : SWIGNode N) ∈ M1.fixed ∪ Z.image SWIGNode.fixed := h rcases Finset.mem_union.mp this with h1 | h2 · exact hfix h1 · rcases Finset.mem_image.mp h2 with ⟨_, _, hEq⟩; cases hEq simp only [dif_neg hfix, dif_neg hfix_M2] -- Observed case: apply IH. have hobs_M1 : (SWIGNode.random u : SWIGNode N) ∈ M1.observed := by have hedge_M1 : M1.dag.edge (SWIGNode.random u) v := M1.dag.mem_parents.mp hwVal_M1 rcases Finset.mem_union.mp (M1.dag_edges_classified _ _ hedge_M1).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix · exact hob · exact absurd h2 huo have hobs_M2 : (SWIGNode.random u : SWIGNode N) ∈ M2.observed := hobs_M1 -- Need: .random u ∈ M2.dag.parents v to apply the index-decrease lemma. -- Since u ∉ Z and .random u ∈ M1.dag.parents v, the splitMono_parents_char -- keeps .random u as a parent in M2. have hwVal_M2 : SWIGNode.random u ∈ M2.dag.parents v := (SWIGGraph.splitMono_parents_char M1.toSWIGGraph Z hZ_obs hZ_fixed v (SWIGNode.random u)).2 (inl ⟨hwVal_M1, fun D hD heq => hu_Z (SWIGNode.random.inj heq ▸ hD)⟩) have hidx_w : (M2.observedIndex ⟨SWIGNode.random u, hobs_M2⟩).val < (M2.observedIndex ⟨v, hv⟩).val := by have hedge_M2 : M2.dag.edge (SWIGNode.random u) v := M2.dag.mem_parents.mp hwVal_M2 have hv_eq : (M2.observedAt ⟨(M2.observedIndex ⟨v, hv⟩).val, (M2.observedIndex ⟨v, hv⟩).isLt⟩).val = v := by have := M2.observedAt_observedIndex ⟨v, hv⟩ convert this have hedge_M2' : M2.dag.edge (SWIGNode.random u) (M2.observedAt ⟨(M2.observedIndex ⟨v, hv⟩).val, (M2.observedIndex ⟨v, hv⟩).isLt⟩).val := by rw [hv_eq]; exact hedge_M2 exact M2.observed_parent_index_lt (M2.observedIndex ⟨v, hv⟩).isLt hedge_M2' hobs_M2 rw [hidx] at hidx_w exact ih _ hidx_w (SWIGNode.random u) hobs_M2 rfl | fixed d => -- `.fixed d` parent: copies through. rw [fixMonoParentMap_apply_fixed M1.toSWIGGraph Z hZ_obs hZ_fixed v _ d hwVal_M1] have huo : (SWIGNode.fixed d : SWIGNode N) ∉ M1.unobserved := by intro h rcases M1.unobserved_is_random _ h with ⟨_, hEq⟩; cases hEq have huo_M2 : (SWIGNode.fixed d : SWIGNode N) ∉ M2.unobserved := huo simp only [dif_neg huo, dif_neg huo_M2] by_cases hfix_M1 : (SWIGNode.fixed d : SWIGNode N) ∈ M1.fixed · have hfix_M2 : (SWIGNode.fixed d : SWIGNode N) ∈ M2.fixed := by change _ ∈ M1.fixed ∪ Z.image SWIGNode.fixed exact mem_union_left _ hfix_M1 simp only [dif_pos hfix_M1, dif_pos hfix_M2] rfl · by_cases hd_Z : d ∈ Z · exfalso have := M1.fixed_outside_fixed_isolated d hfix_M1 have hCh : v ∈ M1.dag.children (SWIGNode.fixed d) := M1.dag.mem_children.mpr (M1.dag.mem_parents.mp hwVal_M1) simpa [this.2] using hCh · have hfix_M2 : (SWIGNode.fixed d : SWIGNode N) ∉ M2.fixed := by intro h rcases Finset.mem_union.mp (show _ ∈ M1.fixed ∪ Z.image SWIGNode.fixed from h) with h1 | h2 · exact hfix_M1 h1 · rcases Finset.mem_image.mp h2 with ⟨d', hd'Z, hEq⟩ have : d = d' := SWIGNode.fixed.inj hEq.symm exact hd_Z (this ▸ hd'Z) simp only [dif_neg hfix_M1, dif_neg hfix_M2] exfalso have hobs : (SWIGNode.fixed d : SWIGNode N) ∈ M1.observed := by have hedge_M1 : M1.dag.edge (SWIGNode.fixed d) v := M1.dag.mem_parents.mp hwVal_M1 rcases Finset.mem_union.mp (M1.dag_edges_classified _ _ hedge_M1).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix_M1 · exact hob · exact absurd h2 huo rcases M1.observed_is_random _ hobs with ⟨_, hEq⟩; cases hEq
theorem fixSet_evalMap_levelset_compat_M2 reviewed
Causalean.SCM

M2-direction level-set evalMap bridge for Rule 2. For the intervention on names Z, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, fix an intervened fixed assignment s' and a latent draw . Suppose the intervened model's own evaluation map at (s', ℓ) already reproduces, at every random copy of a name in Z, the intervention value recorded in s'; then at any observed node v in the intervened model, the intervened model's evaluation map at (s', ℓ) agrees with the base model's evaluation map at the projected fixed assignment and the correspondingly reindexed latent draw.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
s' :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
:
(M'.fixSet Z hZ_obs hZ_fixed).LatentValues
hLS_M2 :
∀ D (hD : D ∈ Z),
(M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ ⟨SWIGNode.random D, mem_union_left _ (hZ_obs D hD)⟩
= s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩
v :
hv :
v ∈ (M'.fixSet Z hZ_obs hZ_fixed).observed
(M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ ⟨v, mem_union_left _ hv⟩
= M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') (valuesProjection (le_of_eq (fixSet_unobserved M' Z hZ_obs hZ_fixed).symm) ℓ) ⟨v, mem_union_left _ (le_of_eq (fixSet_observed M' Z hZ_obs hZ_fixed) hv)⟩
Proof (Lean source)
theorem fixSet_evalMap_levelset_compat_M2 (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) (ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues) (hLS_M2 : ∀ D (hD : D ∈ Z), (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ ⟨SWIGNode.random D, mem_union_left _ (hZ_obs D hD)⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩) {v : SWIGNode N} (hv : v ∈ (M'.fixSet Z hZ_obs hZ_fixed).observed) : (M'.fixSet Z hZ_obs hZ_fixed).evalMap s' ℓ ⟨v, mem_union_left _ hv⟩ = M'.evalMap (M'.fixSetProj Z hZ_obs hZ_fixed s') (valuesProjection (le_of_eq (fixSet_unobserved M' Z hZ_obs hZ_fixed).symm) ℓ) ⟨v, mem_union_left _ (le_of_eq (fixSet_observed M' Z hZ_obs hZ_fixed) hv)⟩ := by classical let M1 := M' let M2 := M1.fixSet Z hZ_obs hZ_fixed have h_obs_eq : M2.observed = M1.observed := rfl have h_unobs : M2.unobserved = M1.unobserved := rfl let s_M1 : M1.FixedValues := M1.fixSetProj Z hZ_obs hZ_fixed s' let ℓ_M1 : M1.LatentValues := valuesProjection (le_of_eq h_unobs.symm) ℓ -- Strong recursion on `M1.observedIndex ⟨v, hv⟩`. suffices h_obs : ∀ (n : ℕ) (w : SWIGNode N) (hw : w ∈ M2.observed), (M1.observedIndex ⟨w, hw⟩).val = n → M2.evalMap s' ℓ ⟨w, mem_union_left _ hw⟩ = M1.evalMap s_M1 ℓ_M1 ⟨w, mem_union_left _ hw⟩ by exact h_obs _ v hv rfl intro n induction n using Nat.strongRecOn with | _ n ih => intro v hv hidx have hv_M1 : v ∈ M1.observed := hv rw [SCM.evalMap_observed_unfold M2 s' ℓ ⟨v, hv⟩, SCM.evalMap_observed_unfold M1 s_M1 ℓ_M1 ⟨v, hv_M1⟩] change M1.structFun ⟨v, hv_M1⟩ (fixMonoParentMap M1.toSWIGGraph Z hZ_obs hZ_fixed v (fun w : {w // w ∈ (M1.splitMono Z hZ_obs hZ_fixed).dag.parents v} => if huo : w.val ∈ M2.unobserved then ℓ ⟨w.val, huo⟩ else if hfix : w.val ∈ M2.fixed then s' ⟨w.val, hfix⟩ else have hedge : M2.dag.edge w.val v := M2.dag.mem_parents.mp w.property have hobs : w.val ∈ M2.observed := by rcases Finset.mem_union.mp (M2.dag_edges_classified _ _ hedge).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix · exact hob · exact absurd h2 huo M2.evalMap s' ℓ ⟨w.val, mem_union_left _ hobs⟩)) = M1.structFun ⟨v, hv_M1⟩ (fun w : {w // w ∈ M1.dag.parents v} => if huo : w.val ∈ M1.unobserved then ℓ_M1 ⟨w.val, huo⟩ else if hfix : w.val ∈ M1.fixed then s_M1 ⟨w.val, hfix⟩ else have hedge : M1.dag.edge w.val v := M1.dag.mem_parents.mp w.property have hobs : w.val ∈ M1.observed := by rcases Finset.mem_union.mp (M1.dag_edges_classified _ _ hedge).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix · exact hob · exact absurd h2 huo M1.evalMap s_M1 ℓ_M1 ⟨w.val, mem_union_left _ hobs⟩) congr 1 funext w rcases w with ⟨wVal, hwVal_M1⟩ cases wVal with | random u => by_cases hu_Z : u ∈ Z · -- u ∈ Z: IH + hLS_M2 replaces the direct `hLevelSet` appeal. rw [fixMonoParentMap_apply_random M1.toSWIGGraph Z hZ_obs hZ_fixed v u hu_Z _ hwVal_M1] have huo_M2 : (SWIGNode.fixed u : SWIGNode N) ∉ M2.unobserved := by intro h rcases M2.unobserved_is_random _ h with ⟨_, hEq⟩; cases hEq have hfix_M2 : (SWIGNode.fixed u : SWIGNode N) ∈ M2.fixed := SCM.fixed_mem_fixSet M1 Z hZ_obs hZ_fixed hu_Z simp only [dif_neg huo_M2, dif_pos hfix_M2] have hobs_M1_u : (SWIGNode.random u : SWIGNode N) ∈ M1.observed := hZ_obs u hu_Z have huo_M1 : (SWIGNode.random u : SWIGNode N) ∉ M1.unobserved := Finset.disjoint_left.mp M1.obs_unobs_disjoint hobs_M1_u have hfix_M1 : (SWIGNode.random u : SWIGNode N) ∉ M1.fixed := by intro h rcases M1.fixed_is_fixed _ h with ⟨_, hEq⟩; cases hEq simp only [dif_neg huo_M1, dif_neg hfix_M1] -- IH at `.random u` via M1.observed_parent_index_lt (edge in M1.dag). have hobs_M2_u : (SWIGNode.random u : SWIGNode N) ∈ M2.observed := hobs_M1_u have hidx_u : (M1.observedIndex ⟨SWIGNode.random u, hobs_M1_u⟩).val < (M1.observedIndex ⟨v, hv_M1⟩).val := by have hedge_M1 : M1.dag.edge (SWIGNode.random u) v := M1.dag.mem_parents.mp hwVal_M1 have hv_eq : (M1.observedAt ⟨(M1.observedIndex ⟨v, hv_M1⟩).val, (M1.observedIndex ⟨v, hv_M1⟩).isLt⟩).val = v := by have := M1.observedAt_observedIndex ⟨v, hv_M1⟩ convert this have hedge_M1' : M1.dag.edge (SWIGNode.random u) (M1.observedAt ⟨(M1.observedIndex ⟨v, hv_M1⟩).val, (M1.observedIndex ⟨v, hv_M1⟩).isLt⟩).val := by rw [hv_eq]; exact hedge_M1 exact M1.observed_parent_index_lt (M1.observedIndex ⟨v, hv_M1⟩).isLt hedge_M1' hobs_M1_u rw [hidx] at hidx_u have h_ih := ih _ hidx_u (SWIGNode.random u) hobs_M2_u rfl -- h_ih: M2 at .random u = M1 at .random u. Combined with hLS_M2: M1 at .random u = z_u. rw [← h_ih] exact (hLS_M2 u hu_Z).symm · -- u ∉ Z: structurally identical to levelset_compat's u ∉ Z branch, -- but IH indexes on M1.observedIndex (natural since the edge is in M1.dag). rw [fixMonoParentMap_apply_random_notMem M1.toSWIGGraph Z hZ_obs hZ_fixed v _ u hu_Z hwVal_M1] by_cases huo : (SWIGNode.random u : SWIGNode N) ∈ M1.unobserved · have huo_M2 : SWIGNode.random u ∈ M2.unobserved := huo simp only [dif_pos huo, dif_pos huo_M2] rfl · have huo_M2 : SWIGNode.random u ∉ M2.unobserved := huo simp only [dif_neg huo, dif_neg huo_M2] by_cases hfix : (SWIGNode.random u : SWIGNode N) ∈ M1.fixed · exfalso rcases M1.fixed_is_fixed _ hfix with ⟨_, hfix_eq⟩; cases hfix_eq · have hfix_M2 : (SWIGNode.random u : SWIGNode N) ∉ M2.fixed := by intro h have : (SWIGNode.random u : SWIGNode N) ∈ M1.fixed ∪ Z.image SWIGNode.fixed := h rcases Finset.mem_union.mp this with h1 | h2 · exact hfix h1 · rcases Finset.mem_image.mp h2 with ⟨_, _, hEq⟩; cases hEq simp only [dif_neg hfix, dif_neg hfix_M2] have hobs_M1 : (SWIGNode.random u : SWIGNode N) ∈ M1.observed := by have hedge_M1 : M1.dag.edge (SWIGNode.random u) v := M1.dag.mem_parents.mp hwVal_M1 rcases Finset.mem_union.mp (M1.dag_edges_classified _ _ hedge_M1).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix · exact hob · exact absurd h2 huo have hobs_M2 : (SWIGNode.random u : SWIGNode N) ∈ M2.observed := hobs_M1 have hidx_w : (M1.observedIndex ⟨SWIGNode.random u, hobs_M1⟩).val < (M1.observedIndex ⟨v, hv_M1⟩).val := by have hedge_M1 : M1.dag.edge (SWIGNode.random u) v := M1.dag.mem_parents.mp hwVal_M1 have hv_eq : (M1.observedAt ⟨(M1.observedIndex ⟨v, hv_M1⟩).val, (M1.observedIndex ⟨v, hv_M1⟩).isLt⟩).val = v := by have := M1.observedAt_observedIndex ⟨v, hv_M1⟩ convert this have hedge_M1' : M1.dag.edge (SWIGNode.random u) (M1.observedAt ⟨(M1.observedIndex ⟨v, hv_M1⟩).val, (M1.observedIndex ⟨v, hv_M1⟩).isLt⟩).val := by rw [hv_eq]; exact hedge_M1 exact M1.observed_parent_index_lt (M1.observedIndex ⟨v, hv_M1⟩).isLt hedge_M1' hobs_M1 rw [hidx] at hidx_w exact ih _ hidx_w (SWIGNode.random u) hobs_M2 rfl | fixed d => -- Unchanged from levelset_compat. rw [fixMonoParentMap_apply_fixed M1.toSWIGGraph Z hZ_obs hZ_fixed v _ d hwVal_M1] have huo : (SWIGNode.fixed d : SWIGNode N) ∉ M1.unobserved := by intro h rcases M1.unobserved_is_random _ h with ⟨_, hEq⟩; cases hEq have huo_M2 : (SWIGNode.fixed d : SWIGNode N) ∉ M2.unobserved := huo simp only [dif_neg huo, dif_neg huo_M2] by_cases hfix_M1 : (SWIGNode.fixed d : SWIGNode N) ∈ M1.fixed · have hfix_M2 : (SWIGNode.fixed d : SWIGNode N) ∈ M2.fixed := by change _ ∈ M1.fixed ∪ Z.image SWIGNode.fixed exact mem_union_left _ hfix_M1 simp only [dif_pos hfix_M1, dif_pos hfix_M2] rfl · by_cases hd_Z : d ∈ Z · exfalso have := M1.fixed_outside_fixed_isolated d hfix_M1 have hCh : v ∈ M1.dag.children (SWIGNode.fixed d) := M1.dag.mem_children.mpr (M1.dag.mem_parents.mp hwVal_M1) simpa [this.2] using hCh · have hfix_M2 : (SWIGNode.fixed d : SWIGNode N) ∉ M2.fixed := by intro h rcases Finset.mem_union.mp (show _ ∈ M1.fixed ∪ Z.image SWIGNode.fixed from h) with h1 | h2 · exact hfix_M1 h1 · rcases Finset.mem_image.mp h2 with ⟨d', hd'Z, hEq⟩ have : d = d' := SWIGNode.fixed.inj hEq.symm exact hd_Z (this ▸ hd'Z) simp only [dif_neg hfix_M1, dif_neg hfix_M2] exfalso have hobs : (SWIGNode.fixed d : SWIGNode N) ∈ M1.observed := by have hedge_M1 : M1.dag.edge (SWIGNode.fixed d) v := M1.dag.mem_parents.mp hwVal_M1 rcases Finset.mem_union.mp (M1.dag_edges_classified _ _ hedge_M1).1 with h1 | h2 · rcases Finset.mem_union.mp h1 with hfx | hob · exact absurd hfx hfix_M1 · exact hob · exact absurd h2 huo rcases M1.observed_is_random _ hobs with ⟨_, hEq⟩; cases hEq
Rect­Identity 2 core · 0 supporting This file provides two almost-everywhere equalities of conditional kernels — a d-separation collapse and a cross-model image comparison — consumed by the discrete-treatment backdoor Rule-2 derivation. ★ obsCondKernel_dSep_collapse_ae★ obsCondKernel_cross_SCM_ae_eq_on_fillZrW

Rule 2 conditional-kernel a.e. helpers

This file provides two almost-everywhere equalities of conditional kernels — a d-separation collapse and a cross-model image comparison — consumed by the discrete-treatment backdoor Rule-2 derivation.

lemma obsCondKernel_dSep_collapse_ae reviewed
Causalean.SCM

D-separation collapse for the post-intervention conditional kernel. For the intervention on names Z, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, with outcome set Y and conditioning set W contained in the observed variables, suppose in the post-intervention SWIG DAG, Y is d-separated from the random copies of Z given W together with the post-intervention fixed set. Then, fixing an intervened fixed assignment s and a measurable outcome set B, for almost every conditioning value on Z.random ∪ W, the intervened model's conditional distribution of Y given Z.random ∪ W assigns B the same probability as its conditional distribution of Y given W alone, evaluated at the W-projection of that conditioning value.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
Y W :
hY :
Y ⊆ M'.observed
hW :
W ⊆ M'.observed
∀ n, Nonempty (swigΩ Ω n)
hdSep :
(M'.fixSet Z hZ_obs hZ_fixed).dag.dSep Y (Z.image SWIGNode.random) (W ∪ (M'.fixSet Z hZ_obs hZ_fixed).fixed)
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))
s :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
B :
hB :
let hZr : Z.image SWIGNode.random ⊆ M'.observed := by intro v hv rcases Finset.mem_image.mp hv with ⟨D, hD, rfl⟩ exact hZ_obs D hD let hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed := union_subset hZr hW ∀ᵐ c ∂((map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW)) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s))), ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y (Z.image SWIGNode.random ∪ W) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW) (s, c)) B
= ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (s, valuesProjection (subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)) B
Proof (Lean source)
lemma obsCondKernel_dSep_collapse_ae (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) [∀ n, StandardBorelSpace (swigΩ Ω n)] [∀ n, Nonempty (swigΩ Ω n)] (hdSep : (M'.fixSet Z hZ_obs hZ_fixed).dag.dSep Y (Z.image SWIGNode.random) (W ∪ (M'.fixSet Z hZ_obs hZ_fixed).fixed)) [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))] (s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) {B : Set (ValuesOn Y (swigΩ Ω))} (hB : MeasurableSet B) : let hZr : Z.image SWIGNode.random ⊆ M'.observed := by intro v hv rcases Finset.mem_image.mp hv with ⟨D, hD, rfl⟩ exact hZ_obs D hD let hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed := Finset.union_subset hZr hW ∀ᵐ c ∂((map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW)) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s))), ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y (Z.image SWIGNode.random ∪ W) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW) (s, c)) B = ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (s, valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)) B := by classical have hZr : Z.image SWIGNode.random ⊆ M'.observed := by intro v hv rcases Finset.mem_image.mp hv with ⟨D, hD, rfl⟩ exact hZ_obs D hD have hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed := Finset.union_subset hZr hW have hDisj_YZr : Disjoint Y (Z.image SWIGNode.random) := hdSep.1 have hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W := Disjoint.mono_right Finset.subset_union_left hdSep.2.2.1 have hDisj_YW : Disjoint Y W := Disjoint.mono_right Finset.subset_union_left hdSep.2.1 -- Abbreviations. let M2 := M'.fixSet Z hZ_obs hZ_fixed let Zr := Z.image SWIGNode.random let μ := M2.obsKernel s have hM2_def : M2 = M'.fixSet Z hZ_obs hZ_fixed := rfl have hZr_def : Zr = Z.image SWIGNode.random := rfl have hμ_def : μ = M2.obsKernel s := rfl have hY_M2 : Y ⊆ M2.observed := by rw [show M2.observed = M'.observed from fixSet_observed M' Z hZ_obs hZ_fixed] exact hY have hW_M2 : W ⊆ M2.observed := by rw [show M2.observed = M'.observed from fixSet_observed M' Z hZ_obs hZ_fixed] exact hW have hZrW_M2 : Zr ∪ W ⊆ M2.observed := by rw [show M2.observed = M'.observed from fixSet_observed M' Z hZ_obs hZ_fixed] exact hZrW have hZr_M2 : Zr ⊆ M2.observed := Finset.subset_union_left.trans hZrW_M2 -- Projection abbreviations. let π_Y := valuesProjection (Ω := swigΩ Ω) hY_M2 let π_W := valuesProjection (Ω := swigΩ Ω) hW_M2 let π_Zr := valuesProjection (Ω := swigΩ Ω) hZr_M2 let π_C := valuesProjection (Ω := swigΩ Ω) hZrW_M2 have hπY_def : π_Y = valuesProjection (Ω := swigΩ Ω) hY_M2 := rfl have hπW_def : π_W = valuesProjection (Ω := swigΩ Ω) hW_M2 := rfl have hπZr_def : π_Zr = valuesProjection (Ω := swigΩ Ω) hZr_M2 := rfl have hπC_def : π_C = valuesProjection (Ω := swigΩ Ω) hZrW_M2 := rfl -- (i) globalMarkov_with_fixed (with Z_fix := M2.fixed) converts the -- d-sep hypothesis into observational conditional independence. have hCI : ObsCondIndep M2 Y Zr W hY_M2 hZr_M2 hW_M2 μ := globalMarkov_with_fixed M2 Y Zr W M2.fixed hY_M2 hZr_M2 hW_M2 (refl _) hdSep s -- (ii) Symmetrize and apply Mathlib's `condIndepFun_iff_condDistrib_…`. have hπY_meas : Measurable π_Y := measurable_valuesProjection _ have hπW_meas : Measurable π_W := measurable_valuesProjection _ have hπZr_meas : Measurable π_Zr := measurable_valuesProjection _ have hπC_meas : Measurable π_C := measurable_valuesProjection _ have hMathlib : (fun ω => condDistrib π_Y (fun ω' => (π_W ω', π_Zr ω')) μ ω) =ᵐ[map (fun ω' => (π_W ω', π_Zr ω')) μ] (fun ω => (ProbabilityTheory.Kernel.prodMkRight (ValuesOn Zr (swigΩ Ω)) (condDistrib π_Y π_W μ)) ω) := (ProbabilityTheory.condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight (f := π_Y) (g := π_Zr) hπY_meas hπZr_meas hπW_meas).mp hCI.symm -- (iii) Measurable equivalence `e : ValuesOn (Zr ∪ W) ≃ᵐ ValuesOn W × ValuesOn Zr` -- via `valuesUnionEquiv` (giving `ValZr × ValW`) composed with `prodComm`. let e : ValuesOn (Zr ∪ W) (swigΩ Ω) ≃ᵐ ValuesOn W (swigΩ Ω) × ValuesOn Zr (swigΩ Ω) := (valuesUnionEquiv (A := Zr) (B := W) hDisj_ZrW).trans (MeasurableEquiv.prodComm (α := ValuesOn Zr (swigΩ Ω)) (β := ValuesOn W (swigΩ Ω))) have he_def : e = (valuesUnionEquiv (A := Zr) (B := W) hDisj_ZrW).trans (MeasurableEquiv.prodComm (α := ValuesOn Zr (swigΩ Ω)) (β := ValuesOn W (swigΩ Ω))) := rfl -- Pointwise: `e ∘ π_C = (π_W, π_Zr)` (both compute via valuesProjection of -- subsets of `Zr ∪ W`). have hW_sub : W ⊆ Zr ∪ W := Finset.subset_union_right have hZr_sub : Zr ⊆ Zr ∪ W := Finset.subset_union_left have h_e_comp : (fun ω => e (π_C ω)) = fun ω => (π_W ω, π_Zr ω) := by funext ω -- `e := (valuesUnionEquiv hDisj_ZrW).trans prodComm` gives at `π_C ω`: -- `prodComm (valuesProjection subset_union_left (π_C ω), -- valuesProjection subset_union_right (π_C ω))` -- = `(valuesProjection subset_union_right (π_C ω), -- valuesProjection subset_union_left (π_C ω))`. -- Reduce LHS to the explicit pair form, then rewrite each coord. have e_left : valuesProjection hW_sub (π_C ω) = π_W ω := by rw [hπW_def, hπC_def] exact congrFun (valuesProjection_comp hW_sub hZrW_M2).symm ω have e_right : valuesProjection hZr_sub (π_C ω) = π_Zr ω := by rw [hπZr_def, hπC_def] exact congrFun (valuesProjection_comp hZr_sub hZrW_M2).symm ω -- Both sides are pairs; use `Prod.ext` and pointwise. apply Prod.ext · -- `(e (π_C ω)).1 = π_W ω` show valuesProjection hW_sub (π_C ω) = π_W ω exact e_left · show valuesProjection hZr_sub (π_C ω) = π_Zr ω exact e_right -- (iv) Use the change-of-variable lemma to transport `hMathlib` from -- `μ.map (π_W, π_Zr)` ≡ `μ.map (e ∘ π_C)` to `μ.map π_C`-a.e. have h_e_pi_C : ⇑e ∘ π_C = fun ω => (π_W ω, π_Zr ω) := by funext ω; exact congrFun h_e_comp ω -- Rewrite `μ.map (π_W, π_Zr)` to `μ.map (e ∘ π_C)`. have hmap_eq : map (fun ω => (π_W ω, π_Zr ω)) μ = map (⇑e ∘ π_C) μ := by rw [h_e_pi_C] -- Apply the (C) helper: condDistrib π_Y (e ∘ π_C) μ (e c) = condDistrib π_Y π_C μ c -- a.e. in c under μ.map π_C. have h_cov : ∀ᵐ c ∂(μ.map π_C), condDistrib π_Y (⇑e ∘ π_C) μ (e c) = condDistrib π_Y π_C μ c := condDistrib_comp_right_measurableEquiv μ e hπY_meas hπC_meas -- Transport `hMathlib` via `ae_of_ae_map` for `e`. -- Step: `hMathlib` is ae on `μ.map (e ∘ π_C) = (μ.map π_C).map e`. have hMathlib' : (fun b => condDistrib π_Y (fun ω' => (π_W ω', π_Zr ω')) μ b) =ᵐ[map (⇑e ∘ π_C) μ] (fun b => (ProbabilityTheory.Kernel.prodMkRight (ValuesOn Zr (swigΩ Ω)) (condDistrib π_Y π_W μ)) b) := by rw [← hmap_eq]; exact hMathlib have hmap_compose : map (⇑e ∘ π_C) μ = map ⇑e (μ.map π_C) := (MeasureTheory.Measure.map_map e.measurable hπC_meas).symm rw [hmap_compose] at hMathlib' have hMathlib_pulled : ∀ᵐ c ∂(μ.map π_C), condDistrib π_Y (fun ω' => (π_W ω', π_Zr ω')) μ (e c) = (ProbabilityTheory.Kernel.prodMkRight (ValuesOn Zr (swigΩ Ω)) (condDistrib π_Y π_W μ)) (e c) := MeasureTheory.ae_of_ae_map (μ := μ.map π_C) (f := ⇑e) e.measurable.aemeasurable hMathlib' -- (v) Bridge `condDistrib` back to `obsCondKernel` via -- `obsCondKernel_ae_eq_condDistrib`, twice. have h_bridge_C : (fun c => M2.obsCondKernel Y (Zr ∪ W) hY_M2 hZrW_M2 (s, c)) =ᵐ[μ.map π_C] condDistrib π_Y π_C μ := obsCondKernel_ae_eq_condDistrib M2 Y (Zr ∪ W) hY_M2 hZrW_M2 s have h_bridge_W : (fun w => M2.obsCondKernel Y W hY_M2 hW_M2 (s, w)) =ᵐ[μ.map π_W] condDistrib π_Y π_W μ := obsCondKernel_ae_eq_condDistrib M2 Y W hY_M2 hW_M2 s -- (vi) The RHS-side bridge transports `h_bridge_W` from `μ.map π_W`-a.e. -- to `μ.map π_C`-a.e. via the projection `π_W^C : ValC → ValW`. -- Note: `μ.map π_W = (μ.map π_C).map π_W^C` because `π_W = π_W^C ∘ π_C`. let π_W_C : ValuesOn (Zr ∪ W) (swigΩ Ω) → ValuesOn W (swigΩ Ω) := valuesProjection hW_sub have hπW_C_def : π_W_C = valuesProjection (Ω := swigΩ Ω) hW_sub := rfl have hπW_C_meas : Measurable π_W_C := measurable_valuesProjection _ have hπW_factor : π_W = π_W_C ∘ π_C := by rw [hπW_def, hπW_C_def, hπC_def] exact valuesProjection_comp hW_sub hZrW_M2 have hmap_W_via_C : μ.map π_W = (μ.map π_C).map π_W_C := by rw [hπW_factor, ← MeasureTheory.Measure.map_map hπW_C_meas hπC_meas] rw [hmap_W_via_C] at h_bridge_W have h_bridge_W_pulled : ∀ᵐ c ∂(μ.map π_C), M2.obsCondKernel Y W hY_M2 hW_M2 (s, π_W_C c) = condDistrib π_Y π_W μ (π_W_C c) := MeasureTheory.ae_of_ae_map (μ := μ.map π_C) (f := π_W_C) hπW_C_meas.aemeasurable h_bridge_W -- (vii) Combine all ae statements and conclude. filter_upwards [h_bridge_C, hMathlib_pulled, h_cov, h_bridge_W_pulled] with c hbC hMl hcov hbW -- Goal: M2.obsCondKernel Y (Zr ∪ W) (s, c) B -- = M2.obsCondKernel Y W (s, π_W_C c) B -- where π_W_C uses `subset_union_right`. rw [hbC] -- Now LHS: condDistrib π_Y π_C μ c B rw [← hcov] -- Now LHS: condDistrib π_Y (e ∘ π_C) μ (e c) B -- … truncated; follow the source link for the rest …
lemma obsCondKernel_cross_SCM_ae_eq_on_fillZrW reviewed
Causalean.SCM

Cross-SCM conditional kernels agree along the fillZrW filled assignment. For the intervention on names Z, whose random copies are observed in the base model and whose fixed copies are not yet part of the base model's fixed coordinates, with outcome set Y and conditioning set W contained in the observed variables, the union of the random copies of Z and W contained in the observed variables with the random copies of Z disjoint from W, fix an intervened fixed assignment s; then for a measurable outcome set B and almost every conditioning value w, taken with respect to the pullback of the base model's law on Z.random ∪ W under the filled-assignment map, the base model's conditional distribution of Y given Z.random ∪ W, evaluated at the filled point built from w, and the intervened model's corresponding conditional distribution, evaluated at the same filled point, assign B the same probability.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
Y W :
hY :
Y ⊆ M'.observed
hW :
W ⊆ M'.observed
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_ZrW :
Disjoint (Z.image SWIGNode.random) W
Nonempty (ValuesOn Y (swigΩ Ω))
CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
B :
hB :
∀ᵐ w ∂((map (valuesProjection hZrW) (M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s))).comap (M'.fillZrW Z hZ_obs hZ_fixed W s)),
(M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B
= ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y (Z.image SWIGNode.random ∪ W) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW) (s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B
Proof (Lean source)
lemma obsCondKernel_cross_SCM_ae_eq_on_fillZrW (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) {B : Set (ValuesOn Y (swigΩ Ω))} (hB : MeasurableSet B) : ∀ᵐ w ∂((map (valuesProjection hZrW) (M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s))).comap (M'.fillZrW Z hZ_obs hZ_fixed W s)), (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B = ((M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y (Z.image SWIGNode.random ∪ W) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW) (s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B := by -- Proof skeleton for the rectangle identity. The measure-uniqueness bridge -- is packaged in the helper lemmas below; this block keeps the notation -- aligned with the obs-side and do-side kernels. -- -- Notation. -- M1 := M', -- M2 := M'.fixSet Z _ _, -- sM1 := M'.fixSetProj Z _ _ s, -- F := M'.fillZrW Z _ _ W s, -- C := Z.image .random ∪ W, -- μ_C := (M1.obsKernel sM1).map π_C (M1 marginal on C) -- ν_C := (M2.obsKernel s ).map π_C (M2 marginal on C) -- μ_F := μ_C.comap F (pullback via the -- measurable embedding F) -- f1 w := M1.obsCondKernel Y C (sM1, F w) B, -- f2 w := M2.obsCondKernel Y C (s , F w) B. -- -- We want `f1 =ᵐ[μ_F] f2`. By -- `MeasureTheory.ae_eq_of_forall_setLIntegral_eq_of_sigmaFinite` it -- suffices to check, for every measurable `A ⊆ ValuesOn W`, -- -- ∫_A f1 dμ_F = ∫_A f2 dμ_F. (★) -- -- Reducing both sides to the rectangle measure -- `M.obsKernel _ (π_C⁻¹ F''A ∩ π_Y⁻¹ B)`: -- -- LHS (★) chain. -- ∫_A f1 dμ_F -- = ∫_{F''A} g1 c dμ_C [MeasurableEmbedding.comap + -- `lintegral_indicator`, -- restriction along F] -- = M1.obsKernel sM1 (π_C⁻¹ F''A ∩ π_Y⁻¹ B) -- [`obsKernel_disintegrate_rect` -- with `M := M1`, `D := F''A`] -- = M2.obsKernel s (π_C⁻¹ F''A ∩ π_Y⁻¹ B) -- [`obsKernel_inter_Wset_Zrand_levelset_eq` -- with `S := π_Y⁻¹ B`] -- -- RHS (★) chain. -- ∫_A f2 dμ_F -- = ∫_{F''A} g2 c dμ_C|_{range F} [same comap rewrite] -- = ∫_{F''A} g2 c dν_C [restricted range measure equality] -- = M2.obsKernel s (π_C⁻¹ F''A ∩ π_Y⁻¹ B) [`obsKernel_disintegrate_rect` -- with `M := M2`] -- -- The two chains coincide exactly after proving the restricted range equality -- -- μ_C |_{range F} = ν_C |_{range F} as measures on range F, (♭) -- -- holds. The π-system of filled-assignment cylinders `{ F''A_W : A_W meas }` -- generates the trace σ-algebra on range F, and -- `obsKernel_inter_Wset_Zrand_levelset_eq` with `S := univ` shows the -- two measures agree on each such cylinder; promoting this to a full -- The proof splits into the measure equality on `range F` and the -- disintegration-uniqueness step on that range. The helper infrastructure -- below packages the measurable-embedding and restricted-measure facts used -- in those two steps. classical let M2 := M'.fixSet Z hZ_obs hZ_fixed let sM1 : M'.FixedValues := M'.fixSetProj Z hZ_obs hZ_fixed s let Zr := Z.image SWIGNode.random let F := M'.fillZrW Z hZ_obs hZ_fixed W s have hM2_def : M2 = M'.fixSet Z hZ_obs hZ_fixed := rfl have hsM1_def : sM1 = M'.fixSetProj Z hZ_obs hZ_fixed s := rfl have hZr_def : Zr = Z.image SWIGNode.random := rfl have hF_def : F = M'.fillZrW Z hZ_obs hZ_fixed W s := rfl have hZrW_M2 : Zr ∪ W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW -- F is a measurable embedding. have hF_emb : MeasurableEmbedding F := measurableEmbedding_fillZrW M' Z hZ_obs hZ_fixed W hDisj_ZrW s -- μ_C and ν_C: M1 and M2 marginal pushforwards on C := Zr ∪ W. let μ_C : Measure (ValuesOn (Zr ∪ W) (swigΩ Ω)) := (M'.obsKernel sM1).map (valuesProjection hZrW) let ν_C : Measure (ValuesOn (Zr ∪ W) (swigΩ Ω)) := (M2.obsKernel s).map (valuesProjection hZrW_M2) have hμC_def : μ_C = (M'.obsKernel sM1).map (valuesProjection (Ω := swigΩ Ω) hZrW) := rfl have hνC_def : ν_C = (M2.obsKernel s).map (valuesProjection (Ω := swigΩ Ω) hZrW_M2) := rfl -- Both μ_C and ν_C are finite (pushforwards of finite measures). have hπC_M1_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hZrW) := measurable_valuesProjection _ have hπC_M2_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hZrW_M2) := measurable_valuesProjection _ haveI : IsFiniteMeasure μ_C := by rw [hμC_def]; exact (M'.obsKernel sM1).isFiniteMeasure_map _ haveI : IsFiniteMeasure ν_C := by rw [hνC_def]; exact (M2.obsKernel s).isFiniteMeasure_map _ ---------------------------------------------------------------- -- **Part A** : `μ_C.restrict (range F) = ν_C.restrict (range F)`. ---------------------------------------------------------------- have hPartA : μ_C.restrict (range F) = ν_C.restrict (range F) := by refine restrict_range_eq_of_forall_image hF_emb μ_C ν_C ?_ intro A hA -- ν_C (F''A) = M2.obsKernel s (π_C^{M2}⁻¹(F''A)) -- μ_C (F''A) = M1.obsKernel sM1 (π_C^{M1}⁻¹(F''A)) -- The cross-SCM cylinder bridge with `S := univ` gives equality. have hImg_meas : MeasurableSet (F '' A) := hF_emb.measurableSet_image' hA have hMap_M1 : μ_C (F '' A) = M'.obsKernel sM1 ((valuesProjection hZrW)⁻¹' (F '' A)) := by rw [hμC_def, MeasureTheory.Measure.map_apply hπC_M1_meas hImg_meas] have hMap_M2 : ν_C (F '' A) = M2.obsKernel s ((valuesProjection hZrW_M2)⁻¹' (F '' A)) := by rw [hνC_def, MeasureTheory.Measure.map_apply hπC_M2_meas hImg_meas] -- Cross-SCM bridge with S := univ. have hBridge : M2.obsKernel s (univ ∩ (valuesProjection hZrW_M2)⁻¹' (F '' A)) = M'.obsKernel sM1 (univ ∩ (valuesProjection hZrW)⁻¹' (F '' A)) := obsKernel_inter_Wset_Zrand_levelset_eq M' Z hZ_obs hZ_fixed W hZrW hDisj_ZrW s MeasurableSet.univ hA rw [Set.univ_inter, Set.univ_inter] at hBridge rw [hMap_M1, hMap_M2, hBridge] ---------------------------------------------------------------- -- **Part B** : disintegration uniqueness on `range F`. -- -- From `hPartA`, the M1 and M2 joint measures agree on every set of -- the form `π_C⁻¹ E ∩ π_Y⁻¹ B` for measurable `E ⊆ range F`. Their -- disintegrations along `π_C` (via `obsKernel_disintegrate_rect`) -- coincide as the same conditional kernel up to a μ_C|_{range F}-null -- set. Concretely, for every measurable `E ⊆ ValuesOn (Zr ∪ W)`: -- -- ∫⁻ c in E ∩ range F, M1.obsCondKernel Y C (sM1, c) B dμ_C -- = M1.obsKernel sM1 (π_C⁻¹ (E ∩ range F) ∩ π_Y⁻¹ B) -- = M2.obsKernel s (π_C⁻¹ (E ∩ range F) ∩ π_Y⁻¹ B) -- bridge -- = ∫⁻ c in E ∩ range F, M2.obsCondKernel Y C (s, c) B dν_C -- = ∫⁻ c in E ∩ range F, M2.obsCondKernel Y C (s, c) B dμ_C -- -- via Part A -- -- Apply `MeasureTheory.ae_eq_of_forall_setLIntegral_eq_of_sigmaFinite` -- to `g1 c := M1.obsCondKernel Y C (sM1, c) B` and -- `g2 c := M2.obsCondKernel Y C (s, c) B` on `μ_C.restrict (range F)`. -- Then transport `g1 ∘ F =ᵐ[μ_F] g2 ∘ F` from -- `g1 =ᵐ[μ_C.restrict (range F)] g2` via -- `MeasurableEmbedding.ae_map_iff` and `hF_emb.map_comap`. -- ---------------------------------------------------------------- -- **Part B** : disintegration uniqueness on `range F`. ---------------------------------------------------------------- -- M2-side `Y ⊆ M2.observed`. have hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY -- Measurability of the π_Y-preimage of B on both sides. have hπY_M1_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hY) := measurable_valuesProjection _ have hπY_M2_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hY_M2) := measurable_valuesProjection _ have hπYB_M1 : MeasurableSet ((valuesProjection (Ω := swigΩ Ω) hY)⁻¹' B) := hπY_M1_meas hB have hπYB_M2 : MeasurableSet ((valuesProjection (Ω := swigΩ Ω) hY_M2)⁻¹' B) := hπY_M2_meas hB -- The integrand functions `f1`, `f2` (M1 and M2 conditional kernels at B). let f1 : ValuesOn (Zr ∪ W) (swigΩ Ω) → ENNReal := fun c => M'.obsCondKernel Y (Zr ∪ W) hY hZrW (sM1, c) B let f2 : ValuesOn (Zr ∪ W) (swigΩ Ω) → ENNReal := fun c => M2.obsCondKernel Y (Zr ∪ W) hY_M2 hZrW_M2 (s, c) B have hf1_meas : Measurable f1 := (ProbabilityTheory.Kernel.measurable_coe _ hB).comp (prodMk measurable_const measurable_id) have hf2_meas : Measurable f2 := (ProbabilityTheory.Kernel.measurable_coe _ hB).comp (prodMk measurable_const measurable_id) -- **Step 1.** For every measurable `A ⊆ ValuesOn W`, -- … truncated; follow the source link for the rest …
Witness­Bridge 4 core · 7 supporting This file isolates the genuinely-hard analytic step of the continuous-Z Rule 2 (backdoor) argument and assembles the cross-SCM bridge obsCondKernel_fixSet_M1_eq_ae_product around it. ★ obsSide_eq_witness★ doSide_M2_condDistrib_eq_M1_witness★ doSide_eq_witness★ obsCondKernel_fixSet_M1_eq_ae_product

Cross-SCM obsCondKernel identity via the posterior witness kernel

This file isolates the genuinely-hard analytic step of the continuous-Z Rule 2 (backdoor) argument and assembles the cross-SCM bridge obsCondKernel_fixSet_M1_eq_ae_product around it.

Posterior witness kernel

Both the obs-side and the do-side equal the posterior witness kernel

(condDistrib C_W (πW ∘ E) μ_lat).map (h t w)

where μ_lat = M.latentProduct, E = M.evalMap s, C_W = M.cutsetLatent Y (Zr∪W) is the latent cut-set, and h is the cut-set override map. This is the law of Y | W under the posterior of the cut-set given W, which — crucially — respects the W–Y confounding allowed by the backdoor criterion. (The old obsCondKernel_struct route pushed the prior latent law forward, giving Y | do(C), which is wrong under confounding; that route is deleted.)

The spine is:

* condDistrib_map_comp (Mathlib helper): transport the obs-level condDistrib π_Y π_{Zr∪W} (obsKernel s) onto the latent space latentProduct, where π ∘ E are the pulled-back coordinate maps. * condDistrib_map_of_condDistrib_fst_eq (witness lemma, CondDistribWitness.lean): given the pointwise factorization Y = h X Z C and the conditional independence C ⊥ X | Z (in condDistrib-equality form), it yields the posterior witness-kernel form of condDistrib Y (X,Z). * the do-side under M2 := M'.fixSet Z mirrors the obs-side (random Zr has no children in M2), and the two witness kernels are identified via fixSet_latentProduct_compat plus the fillZrW override agreement; positivity (Rule 3) transports onto the product νZ ⊗ₘ μW.

Analytic cores

The construction is assembled from the following named lemmas:

* cutset_factor_pointwise — the pointwise factorization π_Y ∘ E = h (π_Zr∘E) (π_W∘E) C_W, together with the OFF-diagonal override characterization h zr w' (π_{C_W} ℓ) = evalMap_overrideC … (valuesUnionMk zr w') ℓ (needed do-side, where the treatment is pinned at t off the M1 diagonal). * cutset_condIndep_condDistrib — the CI C_W ⊥ (π_Zr∘E) | (π_W∘E) under latentProduct, in the condDistrib-pair form the witness lemma consumes, from cutsetLatent_dSep_of_dSep + full_globalMarkov_with_fixed. * obsSide_eq_witness, doSide_eq_witness — the two witness-kernel identities. * doSide_M2_pullback_eq_M1_witness — the fillZrW cross-SCM identification of the M2-pullback W-conditional with the M1 witness kernel. Closed via the no-X witness corollary condDistrib_map_of_funext (Mathlib/CondDistribWitness.lean) plus the override chain evalMap_overrideC_at_self@M2 → evalMap_overrideC_dropZr_on_fillZrWevalMap_overrideC_fixSet_compat_on_fillZrW → the override characterization of h. * obsCondKernel_fixSet_M1_eq_ae_product — the product-form connect + positivity transport (consumed by condDistrib_fixSet_cross_SCM_bridge in Rule2AE).

theorem obsSide_eq_witness reviewed
Causalean.SCM

Obs-side witness-kernel identity (pair-conditioned, on the latent space). Let M be a structural causal model with node sets Y, W and a set of treatment names Z, where Y is observed, the pre-intervention nodes of Z are observed, and W is observed. Suppose the latent cut-set for Y relative to Z's pre-intervention nodes together with W is d-separated, in M's causal graph, from Z's pre-intervention nodes given W and the fixed nodes, and let h be a jointly measurable map such that, at a fixed baseline assignment s, the realized value of Y factors pointwise as h applied to the realized pre-intervention-Z value, the realized W value, and the cut-set's latent value. Then, under M's latent product measure, the conditional law of Y given the pair of realized pre-intervention-Z and W values equals, for almost every such pair, the pushforward under h applied to that pair of the conditional law of the latent cut-set given the realized W value.

Formal statement
M :
SCM N Ω
StandardBorelSpace M.RandomValues
∀ n, Nonempty (swigΩ Ω n)
∀ s :
M.FixedValues, IsFiniteMeasure (M.jointKernel s)
Y W :
Z :
StandardBorelSpace (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
Nonempty (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
Nonempty (ValuesOn Y (swigΩ Ω))
hY :
Y ⊆ M.observed
hZr :
Z.image SWIGNode.random ⊆ M.observed
hW :
W ⊆ M.observed
hdSepCW :
M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)
s :
M.FixedValues
h :
ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)
hh :
Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)
hfac :
∀ ℓ : M.LatentValues,
valuesProjection hY (M.randomToObserved (M.evalMap s ℓ))
= h (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
(fun p : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => condDistrib (fun ℓ : M.LatentValues => valuesProjection hY (M.randomToObserved (M.evalMap s ℓ))) (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)))) M.latentProduct p)
=ᵐ[M.latentProduct.map (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))))] (fun p => (condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct p.2).map (h p.1 p.2))
Proof (Lean source)
theorem obsSide_eq_witness (M : SCM N Ω) [StandardBorelSpace M.RandomValues] [∀ n, StandardBorelSpace (swigΩ Ω n)] [∀ n, Nonempty (swigΩ Ω n)] [∀ s : M.FixedValues, IsFiniteMeasure (M.jointKernel s)] (Y W : Finset (SWIGNode N)) (Z : Finset N) [StandardBorelSpace (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] (hY : Y ⊆ M.observed) (hZr : Z.image SWIGNode.random ⊆ M.observed) (hW : W ⊆ M.observed) (hdSepCW : M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)) (s : M.FixedValues) (h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)) (hh : Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)) (hfac : ∀ ℓ : M.LatentValues, valuesProjection hY (M.randomToObserved (M.evalMap s ℓ)) = h (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)) : (fun p : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => condDistrib (fun ℓ : M.LatentValues => valuesProjection hY (M.randomToObserved (M.evalMap s ℓ))) (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)))) M.latentProduct p) =ᵐ[M.latentProduct.map (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))))] (fun p => (condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct p.2).map (h p.1 p.2)) := by haveI : IsProbabilityMeasure M.latentProduct := inferInstance have hX : Measurable (fun ℓ : M.LatentValues => valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ))) := M.valuesProjection_randomToObserved_evalMap_meas hZr s have hZmeas : Measurable (fun ℓ : M.LatentValues => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) := M.valuesProjection_randomToObserved_evalMap_meas hW s have hCmeas : Measurable (valuesProjection (Ω := swigΩ Ω) (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) := measurable_valuesProjection _ -- The witness lemma's `Y = h X Z C` pointwise (from `hfac`). have hY_eq : (fun ℓ : M.LatentValues => valuesProjection hY (M.randomToObserved (M.evalMap s ℓ))) = fun ℓ => h (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ) := funext hfac have hwit := condDistrib_map_of_condDistrib_fst_eq (Ω := M.LatentValues) (𝒳 := ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (𝒵 := ValuesOn W (swigΩ Ω)) (𝒞 := ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω)) (𝒴 := ValuesOn Y (swigΩ Ω)) (μ := M.latentProduct) (X := fun ℓ => valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ))) (Z := fun ℓ => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) (C := valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (h := h) hX hZmeas hCmeas hh (cutset_condIndep_condDistrib M Y W Z hZr hW hdSepCW s) -- `hwit` conditions `condDistrib (fun ℓ => h (X ℓ)(Z ℓ)(C ℓ)) ...`; rewrite via `hY_eq`. rw [hY_eq] exact hwit
theorem doSide_M2_condDistrib_eq_M1_witness reviewed
Causalean.SCM

Do-side analytic core: the M2 W-conditional equals the M1 witness kernel. Let M' be a structural causal model and Z a set of treatment names with each treatment's pre-intervention node observed and each treatment's post-intervention node not already fixed in M', so that intervening on Z is well-formed; let Y, W be node sets with Y, W, the treatments' pre-intervention nodes, and their union with W all observed and Y disjoint from the treatments' pre-intervention nodes. Suppose no node of W is a descendant, in the intervened model's graph, of any treatment's post-intervention node, and let h be a jointly measurable map that, at a baseline assignment s0 to the original model's fixed nodes, factors the realized outcome as h applied to the realized treatment value, the realized W value, and the latent cut-set's value and additionally, for every candidate treatment/W pair, agrees there with the outcome obtained by instead overriding the baseline assignment s0 to that pair. Then, at the intervened model's slice fixing the treatments to a value t and the remaining fixed nodes to s0, the measure-level conditional law of Y given W equals, for almost every w under the W-marginal of the original model's observational kernel at s0, the pushforward under h t w of the original model's posterior conditional law of the latent cut-set given W.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
Y W :
hY :
Y ⊆ M'.observed
hW :
W ⊆ M'.observed
hZr :
Z.image SWIGNode.random ⊆ M'.observed
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_YZr :
Disjoint Y (Z.image SWIGNode.random)
hWNonDesc :
∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v
StandardBorelSpace M'.RandomValues
Nonempty (ValuesOn Y (swigΩ Ω))
StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues
StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues
StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s0 :
M'.FixedValues
t :
ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)
h :
ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)
hh :
Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)
hfac :
∀ ℓ : M'.LatentValues,
valuesProjection hY (M'.randomToObserved (M'.evalMap s0 ℓ))
= h (valuesProjection hZr (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
hoverride :
∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M'.LatentValues),
h zr w' (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
= M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk zr w') ℓ
(fun w => condDistrib (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY)) (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t)) w)
=ᵐ[(M'.obsKernel s0).map (valuesProjection hW)] (fun w => ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) w).map (h t w))
Proof (Lean source)
theorem doSide_M2_condDistrib_eq_M1_witness (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) (hZr : Z.image SWIGNode.random ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_YZr : Disjoint Y (Z.image SWIGNode.random)) (hWNonDesc : ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v) [StandardBorelSpace M'.RandomValues] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues] [StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s0 : M'.FixedValues) (t : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)) (hh : Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)) (hfac : ∀ ℓ : M'.LatentValues, valuesProjection hY (M'.randomToObserved (M'.evalMap s0 ℓ)) = h (valuesProjection hZr (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)) (hoverride : ∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M'.LatentValues), h zr w' (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ) = M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk zr w') ℓ) : (fun w => condDistrib (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY)) (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t)) w) =ᵐ[(M'.obsKernel s0).map (valuesProjection hW)] (fun w => ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) w).map (h t w)) := by classical set M2 := M'.fixSet Z hZ_obs hZ_fixed with hM2 set s' := M'.fixSetExtend Z hZ_obs hZ_fixed s0 t with hs' set hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY with hhY_M2 set hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW with hhW_M2 set μW := (M'.obsKernel s0).map (valuesProjection hW) with hμW -- Abbreviation: the M2 observed-eval pullback `E2`. set E2 : M2.LatentValues → M2.ObservedValues := fun ℓ => M2.randomToObserved (M2.evalMap s' ℓ) with hE2_def have hE2meas : Measurable E2 := by have hev : Measurable (fun ℓ : M2.LatentValues => M2.evalMap s' ℓ) := by have : M2.evalMap s' = fun ℓ => uncurry M2.evalMap (s', ℓ) := rfl rw [this] exact M2.evalMap_measurable.comp (prodMk measurable_const measurable_id) exact M2.measurable_randomToObserved.comp hev have hπY : Measurable (valuesProjection (Ω := swigΩ Ω) hY_M2) := measurable_valuesProjection hY_M2 have hπW : Measurable (valuesProjection (Ω := swigΩ Ω) hW_M2) := measurable_valuesProjection hW_M2 -- Base alignment: the M2 `W`-marginal at the slice `s'` equals `μW` (Rule 3). have hbase : (M2.obsKernel s').map (valuesProjection hW_M2) = μW := by have hRule3 := obsKernel_fixSet_W_marginal_eq_M1_marginal M' Z hZ_obs hZ_fixed W hW hWNonDesc s' rw [hμW] rw [show (M2.obsKernel s').map (valuesProjection hW_M2) = (M2.obsKernel s').map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) from rfl, hRule3, M'.fixSetProj_fixSetExtend Z hZ_obs hZ_fixed s0 t] -- Step A: transport the M2 LHS `condDistrib π_Y π_W (M2.obsKernel s')` onto -- `M2.latentProduct` via `obsKernel_eq_latentProduct_map` + `condDistrib_map_comp`. have hobs : M2.obsKernel s' = M2.latentProduct.map E2 := M2.obsKernel_eq_latentProduct_map s' have hstepA := condDistrib_map_comp (𝒴 := ValuesOn Y (swigΩ Ω)) M2.latentProduct (φ := E2) (g := valuesProjection hY_M2) (f := valuesProjection hW_M2) hE2meas hπY hπW -- `hstepA : condDistrib π_Y π_W (latentProduct.map E2) -- =ᵐ[(latentProduct.map E2).map π_W] condDistrib (π_Y∘E2) (π_W∘E2) latentProduct`. -- Align the base of `hstepA` to `μW`. have hbase' : (M2.latentProduct.map E2).map (valuesProjection hW_M2) = μW := by rw [← hobs]; exact hbase rw [hbase'] at hstepA -- Step B+C (isolated TRUE core): the M2-pullback condDistrib equals the M1 witness kernel. have hcore := doSide_M2_pullback_eq_M1_witness M' Z hZ_obs hZ_fixed Y W hY hZrW hDisj_YZr hWNonDesc s0 t h hh hoverride -- Align the goal's LHS (over `M2.obsKernel s'`) to `hstepA`'s LHS (over `latentProduct.map E2`) -- via `hobs`, handling the dependent `IsFiniteMeasure` instance with `subst`. refine Filter.EventuallyEq.trans ?_ (hstepA.trans hcore) have hcongr : (condDistrib (valuesProjection hY_M2) (valuesProjection hW_M2) (M2.obsKernel s')) = condDistrib (valuesProjection hY_M2) (valuesProjection hW_M2) (M2.latentProduct.map E2) := by congr 1 rw [hcongr]
theorem doSide_eq_witness reviewed
Causalean.SCM

Do-side per-slice witness identity (M1-witness-kernel form). Let M' be a structural causal model and Z a set of treatment names with each treatment's pre-intervention node observed and each treatment's post-intervention node not already fixed in M'; let Y, W be node sets with Y, W, the treatments' pre-intervention nodes, and their union with W all observed, Y disjoint from the treatments' pre-intervention nodes, and those pre-intervention nodes disjoint from W. Suppose no node of W is a descendant, in the intervened model's graph, of any treatment's post-intervention node, and let h be a jointly measurable map that, at a baseline assignment s0 to the original model's fixed nodes, factors the realized outcome as h applied to the realized treatment value, the realized W value, and the latent cut-set's value, and additionally for every candidate treatment/W pair agrees there with the outcome obtained by instead overriding the baseline assignment s0 to that pair. Then, at the intervened model's slice fixing the treatments to a value t and the remaining fixed nodes to s0, for almost every w under the W-marginal of the original model's observational kernel at s0, the intervened model's conditional-probability kernel for Y given W at (s', w) equals the pushforward under h t w of the original model's posterior conditional law of the latent cut-set given W.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
Y W :
hY :
Y ⊆ M'.observed
hW :
W ⊆ M'.observed
hZr :
Z.image SWIGNode.random ⊆ M'.observed
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_ZrW :
Disjoint (Z.image SWIGNode.random) W
hDisj_YZr :
Disjoint Y (Z.image SWIGNode.random)
hWNonDesc :
∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v
StandardBorelSpace M'.RandomValues
Nonempty (ValuesOn Y (swigΩ Ω))
StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues
StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues
StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s0 :
M'.FixedValues
t :
ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)
h :
ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)
hh :
Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)
hfac :
∀ ℓ : M'.LatentValues,
valuesProjection hY (M'.randomToObserved (M'.evalMap s0 ℓ))
= h (valuesProjection hZr (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
hoverride :
∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M'.LatentValues),
h zr w' (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
= M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk zr w') ℓ
∀ᵐ w ∂((M'.obsKernel s0).map (valuesProjection hW)),
(M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t, w)
= ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) w).map (h t w)
Proof (Lean source)
theorem doSide_eq_witness (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) (hZr : Z.image SWIGNode.random ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) (hDisj_YZr : Disjoint Y (Z.image SWIGNode.random)) (hWNonDesc : ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v) [StandardBorelSpace M'.RandomValues] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues] [StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s0 : M'.FixedValues) (t : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)) (hh : Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)) (hfac : ∀ ℓ : M'.LatentValues, valuesProjection hY (M'.randomToObserved (M'.evalMap s0 ℓ)) = h (valuesProjection hZr (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)) (hoverride : ∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M'.LatentValues), h zr w' (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ) = M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk zr w') ℓ) : ∀ᵐ w ∂((M'.obsKernel s0).map (valuesProjection hW)), (M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t, w) = ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) w).map (h t w) := by -- Witness-route per-slice identity, **M1-witness-kernel form**. The LHS (the M2 -- `W`-conditional intervened at `t`) equals the M1 posterior witness kernel at -- `(t, w)`. The M2 witness chain (`obsCondKernel_ae_eq_condDistrib`@M2 → -- `condDistrib_map_comp`@M2 → the M2 cut-set factorization with trivial `Zr` -- coordinate → the M2 witness identity) and the cross-SCM identification of the M2 -- witness kernel with the M1 witness kernel via `fixSet_latentProduct_compat` + -- `evalMap_overrideC_fixSet_compat_on_fillZrW`, transported onto the common `μW` -- base by Rule 3 (`obsKernel_fixSet_W_marginal_eq_M1_marginal`). The analytic -- core is isolated as `doSide_M2_condDistrib_eq_M1_witness`; here we discharge -- the assembly (obsCondKernelcondDistrib bridge at M2 + base alignment). classical set M2 := M'.fixSet Z hZ_obs hZ_fixed with hM2 set s' := M'.fixSetExtend Z hZ_obs hZ_fixed s0 t with hs' set hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY with hhY_M2 set hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW with hhW_M2 set μW := (M'.obsKernel s0).map (valuesProjection hW) with hμW -- Base alignment: the M2 `W`-marginal at the slice `s'` equals `μW` (Rule 3 + -- `fixSetProj (fixSetExtend s0 t) = s0`). have hbase : (M2.obsKernel s').map (valuesProjection hW_M2) = μW := by have hRule3 := obsKernel_fixSet_W_marginal_eq_M1_marginal M' Z hZ_obs hZ_fixed W hW hWNonDesc s' rw [hμW] rw [show (M2.obsKernel s').map (valuesProjection hW_M2) = (M2.obsKernel s').map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) from rfl, hRule3, M'.fixSetProj_fixSetExtend Z hZ_obs hZ_fixed s0 t] -- Step 1: at M2, `obsCondKernel Y W (s', ·) =ᵐ condDistrib π_Y π_W (M2.obsKernel s')`, -- with base `(M2.obsKernel s').map π_W`. have h1 := M2.obsCondKernel_ae_eq_condDistrib Y W hY_M2 hW_M2 s' rw [hbase] at h1 -- Step 2: the analytic core — that condDistrib equals the M1 witness kernel. have h2 := doSide_M2_condDistrib_eq_M1_witness M' Z hZ_obs hZ_fixed Y W hY hW hZr hZrW hDisj_YZr hWNonDesc s0 t h hh hfac hoverride -- Both `h1` and `h2` are stated over the base `μW`; chain. filter_upwards [h1, h2] with w hw1 hw2 -- `hw1 : M2.obsCondKernel Y W (s', w) = condDistrib π_Y π_W (M2.obsKernel s') w` -- `hw2 : condDistrib π_Y π_W (M2.obsKernel s') w = witness` rw [hw1, hw2]
theorem obsCondKernel_fixSet_M1_eq_ae_product reviewed
Causalean.SCM

Product-form cross-SCM bridge for the do-side conditional kernel. Let M' be a structural causal model and Z a set of treatment names with each treatment's pre-intervention node observed and each treatment's post-intervention node not already fixed in M'; let Y, W be node sets with Y, W, the treatments' pre-intervention nodes, and their union with W all observed, Y disjoint from the treatments' pre-intervention nodes, and those pre-intervention nodes disjoint from W. Suppose that, in the intervened model's graph, no node of W is a descendant of any treatment's post-intervention node, that, in the original model's graph, no node of W is a descendant of any treatment's pre-intervention node, and that in the intervened model's graph, Y is d-separated from the treatments' pre-intervention nodes given W together with the intervened model's fixed nodes. Assume also, at a baseline assignment s0 to the original model's fixed nodes, an overlap condition: the pushforward, under combining a treatment value with a W value, of the product of the treatments' pre-intervention marginal law and the W-marginal law (both taken from the original model's observational kernel at s0) is absolutely continuous with respect to the original model's marginal law on the treatments' pre-intervention nodes together with W, again at s0. Then for almost every pair (t, w) drawn from that product law, the intervened model's conditional-probability kernel for Y given W, evaluated at treatment value t and conditioning value w, equals the original model's conditional-probability kernel for Y given the union of the treatments' pre-intervention nodes and W, evaluated at the combined value (t, w).

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
Y W :
hY :
Y ⊆ M'.observed
hW :
W ⊆ M'.observed
hZr :
Z.image SWIGNode.random ⊆ M'.observed
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_ZrW :
Disjoint (Z.image SWIGNode.random) W
hDisj_YZr :
Disjoint Y (Z.image SWIGNode.random)
hWNonDesc :
∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v
hWNonDescM1 :
∀ D ∈ Z, ∀ w ∈ W, ¬ M'.dag.isAncestor (SWIGNode.random D) w
hdSep :
(M'.fixSet Z hZ_obs hZ_fixed).dag.dSep Y (Z.image SWIGNode.random) (W ∪ (M'.fixSet Z hZ_obs hZ_fixed).fixed)
StandardBorelSpace M'.RandomValues
∀ n, Nonempty (swigΩ Ω n)
Nonempty (ValuesOn Y (swigΩ Ω))
StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues
StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues
StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
∀ s :
M'.FixedValues, IsFiniteMeasure (M'.jointKernel s)
M'.FixedValues, IsFiniteMeasure (M'.obsKernel s)
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s)
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s)
CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s0 :
M'.FixedValues
_hPositivity_ae :
(((M'.obsKernel s0).map (valuesProjection hZr) ⊗ₘ const _ ((M'.obsKernel s0).map (valuesProjection hW))).map (fun p => valuesUnionMk p.1 p.2)) ≪ ((M'.obsKernel s0).map (valuesProjection hZrW))
∀ᵐ p ∂((M'.obsKernel s0).map (valuesProjection hZr) ⊗ₘ const _ ((M'.obsKernel s0).map (valuesProjection hW))),
(M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (M'.fixSetExtend Z hZ_obs hZ_fixed s0 p.1, p.2)
= M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (s0, valuesUnionMk p.1 p.2)
Proof (Lean source)
theorem obsCondKernel_fixSet_M1_eq_ae_product (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) (hZr : Z.image SWIGNode.random ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) (hDisj_YZr : Disjoint Y (Z.image SWIGNode.random)) (hWNonDesc : ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v) (hWNonDescM1 : ∀ D ∈ Z, ∀ w ∈ W, ¬ M'.dag.isAncestor (SWIGNode.random D) w) (hdSep : (M'.fixSet Z hZ_obs hZ_fixed).dag.dSep Y (Z.image SWIGNode.random) (W ∪ (M'.fixSet Z hZ_obs hZ_fixed).fixed)) [StandardBorelSpace M'.RandomValues] [∀ n, StandardBorelSpace (swigΩ Ω n)] [∀ n, Nonempty (swigΩ Ω n)] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues] [StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [∀ s : M'.FixedValues, IsFiniteMeasure (M'.jointKernel s)] [∀ s : M'.FixedValues, IsFiniteMeasure (M'.obsKernel s)] [∀ s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).jointKernel s)] [∀ s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues, IsFiniteMeasure ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s)] [CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s0 : M'.FixedValues) (_hPositivity_ae : (((M'.obsKernel s0).map (valuesProjection hZr) ⊗ₘ const _ ((M'.obsKernel s0).map (valuesProjection hW))).map (fun p => valuesUnionMk p.1 p.2)) ≪ ((M'.obsKernel s0).map (valuesProjection hZrW))) : ∀ᵐ p ∂((M'.obsKernel s0).map (valuesProjection hZr) ⊗ₘ const _ ((M'.obsKernel s0).map (valuesProjection hW))), (M'.fixSet Z hZ_obs hZ_fixed).obsCondKernel Y W ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW) (M'.fixSetExtend Z hZ_obs hZ_fixed s0 p.1, p.2) = M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (s0, valuesUnionMk p.1 p.2) := by -- **Per-slice posterior-witness construction.** `doSide_eq_witness` gives, -- for each treatment value `t`, the equality of LHS and RHS at the slice -- `s' := fixSetExtend s0 t`, a.e. in `w` under `μW = (M'.obsKernel s0).map π_W` -- (the M2 `W`-marginal at the slice equals `μW` literally by Rule 3, -- `obsKernel_fixSet_W_marginal_eq_M1_marginal`). Both sides of that per-slice -- identity are pinned to the posterior witness kernel -- `(condDistrib C_W (π_W∘E1) M1.latentProduct w).map (h t w)` — RHS via -- `obsCondKernel_union_eq_witness`@M1, LHS via the M2 witness chain + cross-SCM -- connect. This proof does not rely on the retired rectangle identity -- `obsKernel_fixSet_rect_eq`. Finally `ae_compProd_of_ae_ae` lifts the iterated -- `∀ᵐ t, ∀ᵐ w` statement to the product `νZ ⊗ₘ const μW`. classical set M2 := M'.fixSet Z hZ_obs hZ_fixed with hM2 set hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY with hhY_M2 set hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW with hhW_M2 set νZ := (M'.obsKernel s0).map (valuesProjection hZr) with hνZ set μW := (M'.obsKernel s0).map (valuesProjection hW) with hμW set lam := νZ ⊗ₘ const _ μW with hlam -- The fill map and the cut-set factorization data, shared by both witness lemmas. set G : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) → ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω) := fun p => valuesUnionMk p.1 p.2 with hG have hG_meas : Measurable G := measurable_valuesUnionMk haveI hΩne : ∀ n, Nonempty (Ω n) := fun n => (inferInstance : Nonempty (swigΩ Ω (SWIGNode.random n))) obtain ⟨h, hh, hfac, hoverride⟩ := cutset_factor_pointwise M' Y W Z hY hZrW s0 -- The shared posterior witness kernel, as a function of the conditioning pair. set wk : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) → Measure (ValuesOn Y (swigΩ Ω)) := fun p => ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) p.2).map (h p.1 p.2) with hwk -- The projection facts: under `G = valuesUnionMk`, the union iso recovers `(t, w)`. have hproj_left : ∀ (t : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w : ValuesOn W (swigΩ Ω)), valuesProjection (subset_union_left) (valuesUnionMk t w) = t := by intro t w; funext v exact valuesUnionMk_apply_left t w v.property have hproj_right : ∀ (t : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w : ValuesOn W (swigΩ Ω)), valuesProjection (subset_union_right) (valuesUnionMk t w) = w := by intro t w; funext v have hnotleft : v.val ∉ Z.image SWIGNode.random := fun hv => (Finset.disjoint_left.mp hDisj_ZrW) hv v.property exact valuesUnionMk_apply_right t w (subset_union_right v.property) hnotleft haveI hM2Markov : IsMarkovKernel (M2.obsCondKernel Y W hY_M2 hW_M2) := by unfold SCM.obsCondKernel; infer_instance haveI hM1Markov : IsMarkovKernel (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW) := by unfold SCM.obsCondKernel; infer_instance -- **RHS = witness** (transport `obsCondKernel_union_eq_witness`@M1 from `μ_C` onto -- `lam` via the product positivity `hPositivity_ae`). This is where positivity is -- consumed. have h_rhs_witness : ∀ᵐ p ∂lam, M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (s0, G p) = wk p := by -- Cutset d-sep at M1, derived from the do-graph d-sep `hdSep`@M2 + criterion (i) -- (`hWNonDescM1`) via the cross-model graph lemma. This REPLACES the deleted -- false hypothesis `hdSepM1 : M'.dag.dSep Y Zr (W∪M'.fixed)`. have hdSepCW : M'.dag.dSep (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M'.fixed) := M'.cutsetLatent_dSep_of_fixSet_dSep Z hZ_obs hZ_fixed Y W hW hWNonDescM1 hdSep have hunion := obsCondKernel_union_eq_witness M' Y W Z hY hZrW hDisj_ZrW hdSepCW s0 h hh hfac -- `lam.map G ≪ μ_C` (the positivity assumption) transports the `μ_C`-a.e. identity. have hAC : map G lam ≪ (M'.obsKernel s0).map (valuesProjection hZrW) := _hPositivity_ae have h_mapG : (fun c => M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (s0, c)) =ᵐ[lam.map G] (fun c => ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) (valuesProjection (subset_union_right) c)).map (h (valuesProjection (subset_union_left) c) (valuesProjection (subset_union_right) c))) := hAC.ae_eq hunion have h_prod := MeasureTheory.ae_of_ae_map hG_meas.aemeasurable h_mapG filter_upwards [h_prod] with p hp rw [hp, hwk] -- Rewrite the projections of `G p = valuesUnionMk p.1 p.2` to `p.1`, `p.2`. simp only [hG, hproj_left, hproj_right] -- **LHS = witness** (the do-side per-slice identity, lifted to `lam`). have h_lhs_witness : ∀ᵐ p ∂lam, M2.obsCondKernel Y W hY_M2 hW_M2 (M'.fixSetExtend Z hZ_obs hZ_fixed s0 p.1, p.2) = wk p := by refine MeasureTheory.Measure.ae_compProd_of_ae_ae ?_ ?_ · -- Measurability of the agreement set. have hfst : Measurable (fun p : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => M2.obsCondKernel Y W hY_M2 hW_M2 (M'.fixSetExtend Z hZ_obs hZ_fixed s0 p.1, p.2)) := by refine (ProbabilityTheory.Kernel.measurable _).comp ?_ exact ((M'.measurable_fixSetExtend Z hZ_obs hZ_fixed s0).comp measurable_fst).prodMk measurable_snd have hwk_meas : Measurable wk := by rw [hwk] exact ProbabilityTheory.Kernel.measurable (witnessKernel M'.latentProduct (Z := fun ℓ => valuesProjection hW (M'.randomToObserved (M'.evalMap s0 ℓ))) (C := valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) hh) exact measurableSet_measure_eq hfst hwk_meas (fun _ => inferInstance) · -- The per-slice posterior witness-kernel identity at `s' := fixSetExtend s0 t`. refine MeasureTheory.ae_of_all _ (fun t => ?_) rw [ProbabilityTheory.Kernel.const_apply] exact SCM.doSide_eq_witness M' Z hZ_obs hZ_fixed Y W hY hW hZr hZrW hDisj_ZrW hDisj_YZr hWNonDesc s0 t h hh hfac hoverride -- Combine: LHS = witness = RHS. filter_upwards [h_lhs_witness, h_rhs_witness] with p hL hR rw [hL, ← hR]
7 supporting declarations (lemmas, instances)
  • measurableSet_measure_eq theorem — The agreement set of two measurable measure-valued maps is measurable.
    hf :
    hg :
    hf_fin :
    ∀ p, IsFiniteMeasure (f p)
    MeasurableSet {p | f p = g p}
    Proof (Lean source)
    theorem measurableSet_measure_eq {γ β : Type*} [MeasurableSpace γ] [MeasurableSpace β] [CountablyGenerated β] {f g : γ → Measure β} (hf : Measurable f) (hg : Measurable g) (hf_fin : ∀ p, IsFiniteMeasure (f p)) : MeasurableSet {p | f p = g p} := by classical -- The countable π-system generated by `countableGeneratingSet β ∪ {univ}`. set C₀ : Set (Set β) := MeasurableSpace.countableGeneratingSet β ∪ {univ} with hC₀ have hC₀_count : C₀.Countable := MeasurableSpace.countable_countableGeneratingSet.union (Set.countable_singleton _) set C : Set (Set β) := generatePiSystem C₀ with hC -- Countability of the generated π-system (image of finite intersections). have hC_count : C.Countable := by have hsub : generatePiSystem C₀ ⊆ (fun F : Finset (Set β) => ⋂₀ (F : Set (Set β))) '' {F : Finset (Set β) | ↑F ⊆ C₀} := by intro t ht induction ht with | base h_s => exact ⟨{_}, by simpa using h_s, by simp⟩ | inter _ _ _ ihs ihu => obtain ⟨Fs, hFs, rfl⟩ := ihs obtain ⟨Fu, hFu, rfl⟩ := ihu refine ⟨Fs ∪ Fu, ?_, ?_⟩ · simp only [Set.mem_setOf_eq, Finset.coe_union, Set.union_subset_iff] exact ⟨hFs, hFu⟩ · simp [Set.sInter_union] refine Set.Countable.mono hsub (Set.Countable.image ?_ _) haveI : Countable C₀ := hC₀_count.to_subtype have hr : {F : Finset (Set β) | ↑F ⊆ C₀} ⊆ range (fun (G : Finset C₀) => G.map (Function.Embedding.subtype _)) := by intro F hF refine ⟨F.subtype (· ∈ C₀), ?_⟩ ext x simp only [Finset.mem_map, Finset.mem_subtype, Function.Embedding.coe_subtype] constructor · rintro ⟨a, ha, rfl⟩; exact ha · intro hx; exact ⟨⟨x, hF hx⟩, by simpa using hx, rfl⟩ exact Set.Countable.mono hr (Set.countable_range _) have hC_pi : IsPiSystem C := isPiSystem_generatePiSystem _ have hC_meas : ∀ s ∈ C, MeasurableSet s := by intro s hs refine generatePiSystem_measurableSet ?_ s hs intro t ht rcases ht with ht | ht · exact MeasurableSpace.measurableSet_countableGeneratingSet ht · rw [Set.mem_singleton_iff] at ht; exact ht ▸ MeasurableSet.univ have hUniv_C : univ ∈ C := subset_generatePiSystem_self _ (inr rfl) have hgenC : (inferInstance : MeasurableSpace β) = MeasurableSpace.generateFrom C := by rw [hC, generateFrom_generatePiSystem_eq, hC₀, ← MeasurableSpace.generateFrom_sup_generateFrom, MeasurableSpace.generateFrom_countableGeneratingSet] have h1 : MeasurableSpace.generateFrom ({univ} : Set (Set β)) = ⊥ := MeasurableSpace.generateFrom_singleton_univ rw [h1, sup_bot_eq] -- Rewrite the agreement set as a countable intersection over `C`. have hset : {p | f p = g p} = ⋂ s ∈ C, {p | f p s = g p s} := by ext p simp only [Set.mem_setOf_eq, Set.mem_iInter] constructor · intro hp s _; rw [hp] · intro hp haveI := hf_fin p refine MeasureTheory.Measure.ext_of_generateFrom_of_iUnion C (fun _ => univ) hgenC hC_pi ?_ (fun _ => hUniv_C) ?_ ?_ · rw [Set.iUnion_const] · intro _; exact (MeasureTheory.measure_ne_top (f p) _) · intro s hs; exact hp s hs rw [hset] -- Each `{p | f p s = g p s}` is measurable; countable intersection. refine MeasurableSet.biInter hC_count (fun s hs => ?_) have hfs : Measurable (fun p => f p s) := (MeasureTheory.Measure.measurable_coe (hC_meas s hs)).comp hf have hgs : Measurable (fun p => g p s) := (MeasureTheory.Measure.measurable_coe (hC_meas s hs)).comp hg exact measurableSet_eq_fun hfs hgs
    Causalean.SCM.measurableSet_measure_eq · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:88
  • obsKernel_eq_latentProduct_map theorem — obsKernel s is the latent product pushed through randomToObserved ∘ evalMap s.
    M :
    SCM N Ω
    s :
    M.FixedValues
    M.obsKernel s = M.latentProduct.map (fun ℓ => M.randomToObserved (M.evalMap s ℓ))
    Proof (Lean source)
    theorem obsKernel_eq_latentProduct_map (M : SCM N Ω) (s : M.FixedValues) : M.obsKernel s = M.latentProduct.map (fun ℓ => M.randomToObserved (M.evalMap s ℓ)) := by have hev : Measurable (fun ℓ : M.LatentValues => M.evalMap s ℓ) := by have : M.evalMap s = fun ℓ => uncurry M.evalMap (s, ℓ) := rfl rw [this] exact M.evalMap_measurable.comp (prodMk measurable_const measurable_id) rw [obsKernel, ProbabilityTheory.Kernel.map_apply _ M.measurable_randomToObserved, jointKernel_apply_eq, MeasureTheory.Measure.map_map M.measurable_randomToObserved hev] rfl
    Causalean.SCM.obsKernel_eq_latentProduct_map · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:178
  • valuesProjection_randomToObserved_evalMap_meas theorem — The pulled-back observed-coordinate projection through randomToObserved ∘ evalMap s is the latent projection of the evaluation, valuesProjection hY ∘ randomToObserved ∘ E. This is definitional unfolding, exposed so downstream condDistrib_map_comp rewrites can name the composite.
    M :
    SCM N Ω
    Y :
    hY :
    Y ⊆ M.observed
    s :
    M.FixedValues
    Measurable (fun ℓ : M.LatentValues => valuesProjection hY (M.randomToObserved (M.evalMap s ℓ)))
    Proof (Lean source)
    theorem valuesProjection_randomToObserved_evalMap_meas (M : SCM N Ω) {Y : Finset (SWIGNode N)} (hY : Y ⊆ M.observed) (s : M.FixedValues) : Measurable (fun ℓ : M.LatentValues => valuesProjection hY (M.randomToObserved (M.evalMap s ℓ))) := by have hev : Measurable (fun ℓ : M.LatentValues => M.evalMap s ℓ) := by have : M.evalMap s = fun ℓ => uncurry M.evalMap (s, ℓ) := rfl rw [this] exact M.evalMap_measurable.comp (prodMk measurable_const measurable_id) exact (measurable_valuesProjection hY).comp (M.measurable_randomToObserved.comp hev)
    Causalean.SCM.valuesProjection_randomToObserved_evalMap_meas · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:196
  • cutset_factor_pointwise theorem — Cut-set factorization, pointwise, at the realized override.
    M :
    SCM N Ω
    ∀ n, Nonempty (Ω n)
    Y W :
    Z :
    hY :
    Y ⊆ M.observed
    hZrW :
    Z.image SWIGNode.random ∪ W ⊆ M.observed
    s :
    M.FixedValues
    ∃ h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω),
    Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2) ∧
    (∀ ℓ : M.LatentValues, valuesProjection hY (M.randomToObserved (M.evalMap s ℓ)) = h (valuesProjection (fun _ hz => hZrW (mem_union_left _ hz)) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (fun _ hw => hZrW (mem_union_right _ hw)) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)) ∧
    (∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M.LatentValues), h zr w' (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ) = M.evalMap_overrideC hY hZrW s (valuesUnionMk zr w') ℓ)
    Proof (Lean source)
    theorem cutset_factor_pointwise (M : SCM N Ω) [∀ n, Nonempty (Ω n)] (Y W : Finset (SWIGNode N)) (Z : Finset N) (hY : Y ⊆ M.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M.observed) (s : M.FixedValues) : ∃ h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω), Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2) ∧ (∀ ℓ : M.LatentValues, valuesProjection hY (M.randomToObserved (M.evalMap s ℓ)) = h (valuesProjection (fun _ hz => hZrW (mem_union_left _ hz)) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (fun _ hw => hZrW (mem_union_right _ hw)) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)) ∧ -- Override-form characterization: `h` evaluated at the cut-set projection of -- *any* latent `ℓ` equals the override map at that `ℓ` with override block -- `(zr, w')`. This pins `h` OFF the realized-`s` diagonal — needed do-side, -- where the treatment coordinate is fixed at `t` (off the M1 diagonal). (∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M.LatentValues), h zr w' (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ) = M.evalMap_overrideC hY hZrW s (valuesUnionMk zr w') ℓ) := by classical have hZr : Z.image SWIGNode.random ⊆ M.observed := fun _ hz => hZrW (mem_union_left _ hz) have hW : W ⊆ M.observed := fun _ hw => hZrW (mem_union_right _ hw) set C := Z.image SWIGNode.random ∪ W with hC_def set CW := M.cutsetLatent Y C with hCW_def have hCWsub : CW ⊆ M.unobserved := M.cutsetLatent_subset Y C -- Default latent vector for filling non-cutset coords. have hNEΩ : ∀ w : SWIGNode N, Nonempty (swigΩ Ω w) := by intro w; cases w <;> exact inferInstance let ℓ₀ : M.LatentValues := fun u => (hNEΩ u.val).some -- The measurable section restoring the cutset coordinates. let extendCutset : ValuesOn CW (swigΩ Ω) → M.LatentValues := fun cwProj u => if h : u.val ∈ CW then cwProj ⟨u.val, h⟩ else ℓ₀ u have hext_meas : Measurable extendCutset := by refine measurable_pi_lambda _ (fun u => ?_) by_cases h : u.val ∈ CW · have : (fun cwProj : ValuesOn CW (swigΩ Ω) => extendCutset cwProj u) = fun cwProj => cwProj ⟨u.val, h⟩ := by funext cwProj; simp [extendCutset, h] rw [this]; exact measurable_pi_apply _ · have : (fun cwProj : ValuesOn CW (swigΩ Ω) => extendCutset cwProj u) = fun _ => ℓ₀ u := by funext cwProj; simp [extendCutset, h] rw [this]; exact measurable_const -- The section restores cutset coordinates. have hext_restore : ∀ cwProj : ValuesOn CW (swigΩ Ω), valuesProjection hCWsub (extendCutset cwProj) = cwProj := by intro cwProj; funext u simp only [valuesProjection, extendCutset, dif_pos u.property] refine ⟨fun zr w c => M.evalMap_overrideC hY hZrW s (valuesUnionMk zr w) (extendCutset c), ?_, ?_, ?_⟩ · -- Joint measurability via `measurable_evalMap_overrideC`. have hcomp : (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn CW (swigΩ Ω) => M.evalMap_overrideC hY hZrW s (valuesUnionMk p.1.1 p.1.2) (extendCutset p.2)) = (fun q : (M.FixedValues × ValuesOn C (swigΩ Ω)) × M.LatentValues => M.evalMap_overrideC hY hZrW q.1.1 q.1.2 q.2) ∘ (fun p => ((s, valuesUnionMk p.1.1 p.1.2), extendCutset p.2)) := by funext p; rfl rw [hcomp] refine (measurable_evalMap_overrideC M hY hZrW).comp ?_ refine prodMk ?_ (hext_meas.comp measurable_snd) refine measurable_const.prodMk ?_ exact measurable_valuesUnionMk.comp measurable_fst · -- Factorization at the realized point. intro ℓ set E := M.randomToObserved (M.evalMap s ℓ) with hE_def -- (a) valuesUnionMk of the two projections of E equals the (Zr∪W)-projection of E. have ha : valuesUnionMk (valuesProjection hZr E) (valuesProjection hW E) = valuesProjection hZrW E := by funext ⟨v, hv⟩ by_cases hvZr : v ∈ Z.image SWIGNode.random · rw [valuesUnionMk_apply_left _ _ hvZr]; rfl · have hvW : v ∈ W := (Finset.mem_union.mp hv).resolve_left hvZr rw [valuesUnionMk_apply_right _ _ hv hvZr]; rfl -- (b) override agrees with `ℓ` after the cutset section, by cutset agreement. have hb : M.evalMap_overrideC hY hZrW s (valuesProjection hZrW E) (extendCutset (valuesProjection hCWsub ℓ)) = M.evalMap_overrideC hY hZrW s (valuesProjection hZrW E) ℓ := by refine evalMap_overrideC_agree_cutset M hY hZrW s _ _ _ ?_ rw [hext_restore] -- (c) the override at its "self" C-value equals the real eval on Y. have hc : M.evalMap_overrideC hY hZrW s (valuesProjection hZrW E) ℓ = valuesProjection hY E := by -- Both sides are the (cast-transported) `evalObservedAux` at observed nodes. have hself : valuesProjection hZrW E = (fun v' : {v // v ∈ C} => (M.observedAt_observedIndex ⟨v'.val, hZrW v'.property⟩) ▸ evalObservedAux M s ℓ (M.observedIndex ⟨v'.val, hZrW v'.property⟩).val (M.observedIndex ⟨v'.val, hZrW v'.property⟩).isLt) := by funext v' change E ⟨v'.val, hZrW v'.property⟩ = _ change M.evalMap s ℓ ⟨v'.val, _⟩ = _ rw [M.evalMap_observed s ℓ _ (hZrW v'.property)] rw [hself, M.evalMap_overrideC_at_self hY hZrW s ℓ] funext v change _ = E ⟨v.val, hY v.property⟩ change _ = M.evalMap s ℓ ⟨v.val, _⟩ rw [M.evalMap_observed s ℓ _ (hY v.property)] -- Assemble. calc valuesProjection hY E = M.evalMap_overrideC hY hZrW s (valuesProjection hZrW E) ℓ := hc.symm _ = M.evalMap_overrideC hY hZrW s (valuesProjection hZrW E) (extendCutset (valuesProjection hCWsub ℓ)) := hb.symm _ = M.evalMap_overrideC hY hZrW s (valuesUnionMk (valuesProjection hZr E) (valuesProjection hW E)) (extendCutset (valuesProjection hCWsub ℓ)) := by rw [ha] · -- Override-form characterization (off-diagonal pinning of `h`). -- `h zr w' (π_{C_W} ℓ) = override (valuesUnionMk zr w') (extendCutset (π_{C_W} ℓ))`, -- and the override depends on the latent only through the cut-set projection, -- so we may replace `extendCutset (π_{C_W} ℓ)` by `ℓ` itself. intro zr w' ℓ change M.evalMap_overrideC hY hZrW s (valuesUnionMk zr w') (extendCutset (valuesProjection hCWsub ℓ)) = M.evalMap_overrideC hY hZrW s (valuesUnionMk zr w') ℓ refine evalMap_overrideC_agree_cutset M hY hZrW s _ _ _ ?_ rw [hext_restore]
    Causalean.SCM.cutset_factor_pointwise · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:215
  • cutset_condIndep_condDistrib theorem — Cut-set conditional independence, in condDistrib-pair form.
    M :
    SCM N Ω
    StandardBorelSpace M.RandomValues
    ∀ n, Nonempty (swigΩ Ω n)
    ∀ s :
    M.FixedValues, IsFiniteMeasure (M.jointKernel s)
    Y W :
    Z :
    StandardBorelSpace (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
    Nonempty (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
    hZr :
    Z.image SWIGNode.random ⊆ M.observed
    hW :
    W ⊆ M.observed
    hdSepCW :
    M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)
    s :
    M.FixedValues
    (fun p : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)))) M.latentProduct p)
    =ᵐ[M.latentProduct.map (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))))] (fun p => condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct p.2)
    Proof (Lean source)
    theorem cutset_condIndep_condDistrib (M : SCM N Ω) [StandardBorelSpace M.RandomValues] [∀ n, StandardBorelSpace (swigΩ Ω n)] [∀ n, Nonempty (swigΩ Ω n)] [∀ s : M.FixedValues, IsFiniteMeasure (M.jointKernel s)] (Y W : Finset (SWIGNode N)) (Z : Finset N) [StandardBorelSpace (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] (hZr : Z.image SWIGNode.random ⊆ M.observed) (hW : W ⊆ M.observed) (hdSepCW : M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)) (s : M.FixedValues) : (fun p : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)))) M.latentProduct p) =ᵐ[M.latentProduct.map (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))))] (fun p => condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct p.2) := by classical set Zr := Z.image SWIGNode.random with hZr_def set CW := M.cutsetLatent Y (Zr ∪ W) with hCW_def have hCWsub : CW ⊆ M.unobserved := M.cutsetLatent_subset Y (Zr ∪ W) -- Subset facts into `randomVars`. have hobs_rv : M.observed ⊆ M.randomVars := by intro v hv; exact Finset.mem_union_left _ hv have hunobs_rv : M.unobserved ⊆ M.randomVars := by intro v hv; exact Finset.mem_union_right _ hv have hZr_rv : Zr ⊆ M.randomVars := hZr.trans hobs_rv have hW_rv : W ⊆ M.randomVars := hW.trans hobs_rv have hCW_rv : CW ⊆ M.randomVars := hCWsub.trans hunobs_rv -- Bridge: for an observed set `D`, projecting `randomToObserved (evalMap s ℓ)` -- equals projecting `evalMap s ℓ` directly (same underlying values). have hbridge_obs : ∀ {D : Finset (SWIGNode N)} (hD : D ⊆ M.observed) (hD_rv : D ⊆ M.randomVars) (ℓ : M.LatentValues), valuesProjection hD (M.randomToObserved (M.evalMap s ℓ)) = valuesProjection hD_rv (M.evalMap s ℓ) := by intro D hD hD_rv ℓ; funext v; rfl -- Bridge: for the latent cutset, projecting `evalMap s ℓ` equals projecting `ℓ`. have hbridge_lat : ∀ ℓ : M.LatentValues, valuesProjection hCW_rv (M.evalMap s ℓ) = valuesProjection hCWsub ℓ := by intro ℓ; funext v change M.evalMap s ℓ ⟨v.val, hCW_rv v.property⟩ = ℓ ⟨v.val, hCWsub v.property⟩ rw [M.evalMap_unobserved s ℓ _ (hCWsub v.property)] -- Measurability of the pulled-back coordinate maps (as compositions with evalMap s). have hev : Measurable (fun ℓ : M.LatentValues => M.evalMap s ℓ) := by have : M.evalMap s = fun ℓ => uncurry M.evalMap (s, ℓ) := rfl rw [this] exact M.evalMap_measurable.comp (prodMk measurable_const measurable_id) -- Abbreviations for the pulled-back coordinate maps. set Xmap : M.LatentValues → ValuesOn Zr (swigΩ Ω) := fun ℓ => valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)) with hX_def set Zmap : M.LatentValues → ValuesOn W (swigΩ Ω) := fun ℓ => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)) with hZmap_def set Cmap : M.LatentValues → ValuesOn CW (swigΩ Ω) := valuesProjection hCWsub with hC_def have hXmeas : Measurable Xmap := (measurable_valuesProjection hZr).comp (M.measurable_randomToObserved.comp hev) have hZmeas : Measurable Zmap := (measurable_valuesProjection hW).comp (M.measurable_randomToObserved.comp hev) have hCmeas : Measurable Cmap := measurable_valuesProjection hCWsub -- Step 1: cutset graph d-sep is now a direct hypothesis; global Markov -- (FullCondIndep under jointKernel) follows. (Previously derived internally -- via `cutsetLatent_dSep_of_dSep` from `dSep Y Zr`, which is FALSE at M1; the -- cutset d-sep `dSep C_W Zr` is the satisfiable input and is threaded directly.) have hdSepCW : M.dag.dSep CW Zr (W ∪ M.fixed) := hdSepCW have hDisj_CWZr : Disjoint CW Zr := by rw [Finset.disjoint_left]; intro a haCW haZr exact not_obs_of_unobs M.toSWIGGraph (hCWsub haCW) (hZr haZr) have hDisj_CWW : Disjoint CW W := by rw [Finset.disjoint_left]; intro a haCW haW exact not_obs_of_unobs M.toSWIGGraph (hCWsub haCW) (hW haW) have hFCI : FullCondIndep M CW Zr W hCW_rv hZr_rv hW_rv (M.jointKernel s) := full_globalMarkov_with_fixed M CW Zr W M.fixed hCW_rv hZr_rv hW_rv (refl _) hdSepCW s -- `Zr ⟂ CW | W` form (swap X↔Y), which the Mathlib iff consumes as `g ⟂ᵢ[k] f`. have hFCI_symm : FullCondIndep M Zr CW W hZr_rv hCW_rv hW_rv (M.jointKernel s) := fullCondIndep_symm M hCW_rv hZr_rv hW_rv hFCI haveI : IsProbabilityMeasure M.latentProduct := inferInstance -- Measurability of the `valuesProjection` maps on `RandomValues`. have hCW_proj_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hCW_rv) := measurable_valuesProjection hCW_rv have hZr_proj_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hZr_rv) := measurable_valuesProjection hZr_rv have hW_proj_meas : Measurable (valuesProjection (Ω := swigΩ Ω) hW_rv) := measurable_valuesProjection hW_rv -- Step 2: Mathlib iff turns `FullCondIndep` into a condDistrib-pair equality -- under `jointKernel s`, conditioning on the pair `(W, Zr)`. have hCI_joint : (fun p => condDistrib (valuesProjection hCW_rv) (fun ξ => (valuesProjection hW_rv ξ, valuesProjection hZr_rv ξ)) (M.jointKernel s) p) =ᵐ[(M.jointKernel s).map (fun ξ => (valuesProjection hW_rv ξ, valuesProjection hZr_rv ξ))] (fun p => ((condDistrib (valuesProjection hCW_rv) (valuesProjection hW_rv) (M.jointKernel s)).prodMkRight _) p) := by have := (ProbabilityTheory.condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight (μ := M.jointKernel s) (f := valuesProjection hCW_rv) (g := valuesProjection hZr_rv) (k := valuesProjection hW_rv) hCW_proj_meas hZr_proj_meas hW_proj_meas).mp hFCI_symm exact this -- The two coordinate maps on `RandomValues`, and their compositions with `evalMap s`. set Wmap_rv : M.RandomValues → ValuesOn W (swigΩ Ω) := valuesProjection hW_rv with hWmap_rv set Zrmap_rv : M.RandomValues → ValuesOn Zr (swigΩ Ω) := valuesProjection hZr_rv with hZrmap_rv set CWmap_rv : M.RandomValues → ValuesOn CW (swigΩ Ω) := valuesProjection hCW_rv with hCWmap_rv set pairWZr : M.RandomValues → ValuesOn W (swigΩ Ω) × ValuesOn Zr (swigΩ Ω) := fun ξ => (Wmap_rv ξ, Zrmap_rv ξ) with hpairWZr have hpairWZr_meas : Measurable pairWZr := hW_proj_meas.prodMk hZr_proj_meas -- Rewrite `jointKernel s` as the pushforward of `latentProduct`. have hjk : M.jointKernel s = M.latentProduct.map (fun ℓ => M.evalMap s ℓ) := jointKernel_apply_eq M s simp only [hjk] at hCI_joint -- Compositions with `evalMap s` reduce to `Zmap`, `Xmap`, `Cmap`. have hcomp_pair : pairWZr ∘ (fun ℓ => M.evalMap s ℓ) = fun ℓ => (Zmap ℓ, Xmap ℓ) := by funext ℓ simp only [hpairWZr, hWmap_rv, hZrmap_rv, Function.comp_apply, hZmap_def, hX_def] rw [hbridge_obs hW hW_rv ℓ, hbridge_obs hZr hZr_rv ℓ] have hcomp_W : Wmap_rv ∘ (fun ℓ => M.evalMap s ℓ) = Zmap := by funext ℓ; simp only [hWmap_rv, Function.comp_apply, hZmap_def] rw [hbridge_obs hW hW_rv ℓ] have hcomp_CW : CWmap_rv ∘ (fun ℓ => M.evalMap s ℓ) = Cmap := by funext ℓ change CWmap_rv (M.evalMap s ℓ) = Cmap ℓ rw [hbridge_lat ℓ] -- Transfer the pair-conditioned `condDistrib` onto `latentProduct`. have htr_pair := condDistrib_map_comp (𝒴 := ValuesOn CW (swigΩ Ω)) M.latentProduct (φ := fun ℓ => M.evalMap s ℓ) (g := CWmap_rv) (f := pairWZr) hev hCW_proj_meas hpairWZr_meas have htr_W := condDistrib_map_comp (𝒴 := ValuesOn CW (swigΩ Ω)) M.latentProduct (φ := fun ℓ => M.evalMap s ℓ) (g := CWmap_rv) (f := Wmap_rv) hev hCW_proj_meas hW_proj_meas -- The `(W, Zr)`-ordered latent pair map and its marginal measure facts. set pairWZr_lat : M.LatentValues → ValuesOn W (swigΩ Ω) × ValuesOn Zr (swigΩ Ω) := fun ℓ => (Zmap ℓ, Xmap ℓ) with hpairWZr_lat have hpairWZr_lat_meas : Measurable pairWZr_lat := hZmeas.prodMk hXmeas -- Push `htr_pair`/`htr_W`/`hCI_joint` filters into `LP.map (·∘E)` form. rw [MeasureTheory.Measure.map_map hpairWZr_meas hev, hcomp_pair, hcomp_CW] at htr_pair rw [MeasureTheory.Measure.map_map hpairWZr_meas hev, hcomp_pair] at hCI_joint rw [MeasureTheory.Measure.map_map hW_proj_meas hev, hcomp_W, hcomp_CW] at htr_W -- `htr_pair` now: condDistrib CWmap_rv pairWZr (LP.map E) =ᵐ[LP.map pairWZr_lat] -- condDistrib Cmap pairWZr_lat LP -- `hCI_joint` now RHS uses prodMkRight of condDistrib CWmap_rv Wmap_rv (LP.map E). -- Reduce prodMkRight to evaluation at `.1`. have hCI_joint' : (fun p => condDistrib CWmap_rv pairWZr (M.latentProduct.map (fun ℓ => M.evalMap s ℓ)) p) =ᵐ[M.latentProduct.map pairWZr_lat] (fun p => condDistrib CWmap_rv Wmap_rv (M.latentProduct.map (fun ℓ => M.evalMap s ℓ)) p.1) := by filter_upwards [hCI_joint] with p hp rw [hp, ProbabilityTheory.Kernel.prodMkRight_apply] -- Lift `htr_W` from the `W`-marginal to the pair-marginal along `fst`. have htr_W_fst : (fun p => condDistrib CWmap_rv Wmap_rv (M.latentProduct.map (fun ℓ => M.evalMap s ℓ)) p.1) =ᵐ[M.latentProduct.map pairWZr_lat] (fun p : ValuesOn W (swigΩ Ω) × ValuesOn Zr (swigΩ Ω) => condDistrib Cmap Zmap M.latentProduct p.1) := by have hfst_marg : (M.latentProduct.map pairWZr_lat).map fst = M.latentProduct.map Zmap := by rw [MeasureTheory.Measure.map_map measurable_fst hpairWZr_lat_meas]; rfl have := MeasureTheory.ae_eq_comp (μ := M.latentProduct.map pairWZr_lat) (f := fst) (g := fun q => condDistrib CWmap_rv Wmap_rv (M.latentProduct.map (fun ℓ => M.evalMap s ℓ)) q) (g' := fun q => condDistrib Cmap Zmap M.latentProduct q) measurable_fst.aemeasurable (by rw [hfst_marg]; exact htr_W) exact this -- Assemble the `(W, Zr)`-ordered equality on `LP.map pairWZr_lat`. have keyWZr : (fun p => condDistrib Cmap pairWZr_lat M.latentProduct p) =ᵐ[M.latentProduct.map pairWZr_lat] (fun p : ValuesOn W (swigΩ Ω) × ValuesOn Zr (swigΩ Ω) => condDistrib Cmap Zmap M.latentProduct p.1) := (htr_pair.symm.trans hCI_joint').trans htr_W_fst -- Swap `(W, Zr)` to `(Zr, W)` via the product-comm measurable equivalence. set e : (ValuesOn W (swigΩ Ω) × ValuesOn Zr (swigΩ Ω)) ≃ᵐ (ValuesOn Zr (swigΩ Ω) × ValuesOn W (swigΩ Ω)) := MeasurableEquiv.prodComm with he_def have hpair_swap : (fun ℓ => (Xmap ℓ, Zmap ℓ)) = e ∘ pairWZr_lat := by funext ℓ; rfl -- `condDistrib Cmap (e ∘ pairWZr_lat) LP (e p) = condDistrib Cmap pairWZr_lat LP p`, a.e. have hreparam := condDistrib_comp_right_measurableEquiv (μ := M.latentProduct) (Y := Cmap) (X := pairWZr_lat) e hCmeas hpairWZr_lat_meas -- Transport the goal (over `LP.map (Xmap, Zmap) = (LP.map pairWZr_lat).map e`) to `keyWZr`. have hmap_e : M.latentProduct.map (fun ℓ => (Xmap ℓ, Zmap ℓ)) = (M.latentProduct.map pairWZr_lat).map e := by rw [hpair_swap, ← MeasureTheory.Measure.map_map e.measurable hpairWZr_lat_meas] -- Final: rewrite the goal's conditioning into `Xmap`/`Zmap`, then chain. change (fun p => condDistrib Cmap (fun ℓ => (Xmap ℓ, Zmap ℓ)) M.latentProduct p) =ᵐ[M.latentProduct.map (fun ℓ => (Xmap ℓ, Zmap ℓ))] (fun p => condDistrib Cmap Zmap M.latentProduct p.2) rw [hmap_e] -- On `(LP.map pairWZr_lat).map e`, pull back along the measurable embedding `e`. rw [EventuallyEq, e.measurableEmbedding.ae_map_iff] filter_upwards [keyWZr, hreparam] with p hkey hrep -- LHS at `e p`: condDistrib Cmap (Xmap,Zmap) LP (e p) = condDistrib Cmap pairWZr_lat LP p. have hLHS : condDistrib Cmap (fun ℓ => (Xmap ℓ, Zmap ℓ)) M.latentProduct (e p) = condDistrib Cmap pairWZr_lat M.latentProduct p := by rw [hpair_swap]; exact hrep change condDistrib Cmap (fun ℓ => (Xmap ℓ, Zmap ℓ)) M.latentProduct (e p) = condDistrib Cmap Zmap M.latentProduct (e p).2 rw [hLHS, hkey] -- RHS: `condDistrib Cmap Zmap LP p.1 = condDistrib Cmap Zmap LP (e p).2`. rfl
    Causalean.SCM.cutset_condIndep_condDistrib · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:372
  • obsCondKernel_union_eq_witness theorem — The (Zr∪W)-conditional packaged as the witness kernel.
    M :
    SCM N Ω
    StandardBorelSpace M.RandomValues
    ∀ n, Nonempty (swigΩ Ω n)
    ∀ s :
    M.FixedValues, IsFiniteMeasure (M.jointKernel s)
    Y W :
    Z :
    StandardBorelSpace (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
    Nonempty (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
    Nonempty (ValuesOn Y (swigΩ Ω))
    CountableOrCountablyGenerated M.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    hY :
    Y ⊆ M.observed
    hZrW :
    Z.image SWIGNode.random ∪ W ⊆ M.observed
    hDisj_ZrW :
    Disjoint (Z.image SWIGNode.random) W
    hdSepCW :
    M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)
    s :
    M.FixedValues
    h :
    ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)
    hh :
    Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)
    hfac :
    ∀ ℓ : M.LatentValues,
    valuesProjection hY (M.randomToObserved (M.evalMap s ℓ))
    = h (valuesProjection ((subset_union_left (s₁ := Z.image SWIGNode.random) (s₂ := W)).trans hZrW) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection ((subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)).trans hZrW) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
    (fun c => M.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (s, c))
    =ᵐ[(M.obsKernel s).map (valuesProjection hZrW)] (fun c => ((condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => valuesProjection (Finset.subset_union_right.trans hZrW) (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct) (valuesProjection (subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)).map (h (valuesProjection (subset_union_left (s₁ := Z.image SWIGNode.random) (s₂ := W)) c) (valuesProjection (subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)))
    Proof (Lean source)
    theorem obsCondKernel_union_eq_witness (M : SCM N Ω) [StandardBorelSpace M.RandomValues] [∀ n, StandardBorelSpace (swigΩ Ω n)] [∀ n, Nonempty (swigΩ Ω n)] [∀ s : M.FixedValues, IsFiniteMeasure (M.jointKernel s)] (Y W : Finset (SWIGNode N)) (Z : Finset N) [StandardBorelSpace (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [CountableOrCountablyGenerated M.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (hY : Y ⊆ M.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) (hdSepCW : M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)) (s : M.FixedValues) (h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)) (hh : Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)) (hfac : ∀ ℓ : M.LatentValues, valuesProjection hY (M.randomToObserved (M.evalMap s ℓ)) = h (valuesProjection ((subset_union_left (s₁ := Z.image SWIGNode.random) (s₂ := W)).trans hZrW) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection ((subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)).trans hZrW) (M.randomToObserved (M.evalMap s ℓ))) (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)) : (fun c => M.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (s, c)) =ᵐ[(M.obsKernel s).map (valuesProjection hZrW)] (fun c => ((condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M.LatentValues => valuesProjection (Finset.subset_union_right.trans hZrW) (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct) (valuesProjection (subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c)).map (h (valuesProjection (subset_union_left (s₁ := Z.image SWIGNode.random) (s₂ := W)) c) (valuesProjection (subset_union_right (s₁ := Z.image SWIGNode.random) (s₂ := W)) c))) := by classical have hZr : Z.image SWIGNode.random ⊆ M.observed := Finset.subset_union_left.trans hZrW have hW : W ⊆ M.observed := Finset.subset_union_right.trans hZrW -- Abbreviations: the observed-eval pullback `E` and the conditioning maps. set E : M.LatentValues → M.ObservedValues := fun ℓ => M.randomToObserved (M.evalMap s ℓ) with hE_def have hEmeas : Measurable E := M.measurable_randomToObserved.comp (by have : (fun ℓ : M.LatentValues => M.evalMap s ℓ) = fun ℓ => uncurry M.evalMap (s, ℓ) := rfl rw [show E = M.randomToObserved ∘ (fun ℓ => M.evalMap s ℓ) from rfl] at * exact M.evalMap_measurable.comp (measurable_const.prodMk measurable_id)) have hπY : Measurable (valuesProjection (Ω := swigΩ Ω) hY) := measurable_valuesProjection hY have hπZrW : Measurable (valuesProjection (Ω := swigΩ Ω) hZrW) := measurable_valuesProjection hZrW -- Step 1: obsCondKernel ↔ condDistrib. have h1 := M.obsCondKernel_ae_eq_condDistrib Y (Z.image SWIGNode.random ∪ W) hY hZrW s -- Step 2: transport the condDistrib onto `latentProduct` along `E`. have hobs : M.obsKernel s = M.latentProduct.map E := M.obsKernel_eq_latentProduct_map s have h2 := condDistrib_map_comp (𝒴 := ValuesOn Y (swigΩ Ω)) M.latentProduct (φ := E) (g := valuesProjection hY) (f := valuesProjection hZrW) hEmeas hπY hπZrW -- Step 3: reparametrize the `πZrW∘E` conditioning by the union iso. have h3 := condDistrib_comp_right_measurableEquiv (Ω := ValuesOn Y (swigΩ Ω)) M.latentProduct (Y := valuesProjection hY ∘ E) (X := valuesProjection hZrW ∘ E) (valuesUnionEquiv hDisj_ZrW) (hπY.comp hEmeas) (hπZrW.comp hEmeas) -- Step 4: the witness identity (pair-conditioned). have h4 := obsSide_eq_witness M Y W Z hY hZr hW hdSepCW s h hh hfac -- The pair map equals `e ∘ (π_{Zr∪W} ∘ E)` (both pick the `Zr`- and `W`-coords). have hpair : (fun ℓ : M.LatentValues => (valuesProjection hZr (E ℓ), valuesProjection hW (E ℓ))) = (⇑(valuesUnionEquiv hDisj_ZrW)) ∘ (valuesProjection hZrW ∘ E) := by funext ℓ; rfl -- Common base measure `ν` and the base alignments. have hbase1 : map (valuesProjection hZrW) (M.obsKernel s) = map (valuesProjection hZrW ∘ E) M.latentProduct := by rw [hobs, MeasureTheory.Measure.map_map hπZrW hEmeas] simp only [← hobs] at h2 -- Chain h1, h2: obsCondKernel = condDistrib of the pulled-back coords. have h12 := h1.trans h2 -- Transport h4 from base `map pair lat` to `ν` via the iso `e`. have hh4base : map (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)))) M.latentProduct = map (valuesUnionEquiv hDisj_ZrW) (map (valuesProjection hZrW ∘ E) M.latentProduct) := by rw [show (fun ℓ : M.LatentValues => (valuesProjection hZr (M.randomToObserved (M.evalMap s ℓ)), valuesProjection hW (M.randomToObserved (M.evalMap s ℓ)))) = (⇑(valuesUnionEquiv hDisj_ZrW)) ∘ (valuesProjection hZrW ∘ E) from hpair, ← MeasureTheory.Measure.map_map (valuesUnionEquiv hDisj_ZrW).measurable (hπZrW.comp hEmeas)] rw [hh4base] at h4 -- The witness kernel (its coe is defeq to `h4`'s RHS), used for measurability. have hwk_meas : Measurable (fun p : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω) => (condDistrib (valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) M.latentProduct p.2).map (h p.1 p.2)) := ProbabilityTheory.Kernel.measurable (witnessKernel M.latentProduct (Z := fun ℓ => valuesProjection hW (M.randomToObserved (M.evalMap s ℓ))) (C := valuesProjection (M.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) hh) have h4' := (MeasureTheory.ae_map_iff (valuesUnionEquiv hDisj_ZrW).measurable.aemeasurable (measurableSet_measure_eq (ProbabilityTheory.Kernel.measurable _) hwk_meas (fun _ => inferInstance))).mp h4 -- Final assembly (all a.e. statements share base `ν = map (πZrW ∘ E) latentProduct`). rw [hbase1] at h12 ⊢ filter_upwards [h12, h3, h4'] with c hc12 hc3 hc4 rw [hc12, ← hc3] exact hc4
    Causalean.SCM.obsCondKernel_union_eq_witness · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:706
  • doSide_M2_pullback_eq_M1_witness theorem — Do-side cross-SCM core: the M2-pullback W-conditional on M2.latentProduct equals the M1 posterior witness kernel.
    M' :
    SCM N Ω
    Z :
    hZ_obs :
    ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
    hZ_fixed :
    ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
    Y W :
    hY :
    Y ⊆ M'.observed
    hZrW :
    Z.image SWIGNode.random ∪ W ⊆ M'.observed
    hDisj_YZr :
    Disjoint Y (Z.image SWIGNode.random)
    hWNonDesc :
    ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v
    StandardBorelSpace M'.RandomValues
    Nonempty (ValuesOn Y (swigΩ Ω))
    StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
    Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))
    StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues
    StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues
    StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
    Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))
    CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))
    MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
    s0 :
    M'.FixedValues
    t :
    ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)
    h :
    ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)
    hh :
    Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)
    hoverride :
    ∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M'.LatentValues),
    h zr w' (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ)
    = M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk zr w') ℓ
    (fun w => condDistrib (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ∘ fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ((M'.fixSet Z hZ_obs hZ_fixed).evalMap (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t) ℓ)) (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ (fun _ hw => hZrW (mem_union_right _ hw))) ∘ fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ((M'.fixSet Z hZ_obs hZ_fixed).evalMap (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t) ℓ)) (M'.fixSet Z hZ_obs hZ_fixed).latentProduct w)
    =ᵐ[(M'.obsKernel s0).map (valuesProjection (fun _ hw => hZrW (mem_union_right _ hw)))] (fun w => ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection (fun _ hw => hZrW (mem_union_right _ hw)) (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) w).map (h t w))
    Proof (Lean source)
    theorem doSide_M2_pullback_eq_M1_witness (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_YZr : Disjoint Y (Z.image SWIGNode.random)) (hWNonDesc : ∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) v) [StandardBorelSpace M'.RandomValues] [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [StandardBorelSpace (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [Nonempty (ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω))] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValues] [StandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValues] [StandardBorelSpace (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [Nonempty (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))] [CountableOrCountablyGenerated (M'.fixSet Z hZ_obs hZ_fixed).FixedValues (ValuesOn W (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s0 : M'.FixedValues) (t : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (h : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) → ValuesOn W (swigΩ Ω) → ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) → ValuesOn Y (swigΩ Ω)) (hh : Measurable (fun p : (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) × ValuesOn W (swigΩ Ω)) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h p.1.1 p.1.2 p.2)) (hoverride : ∀ (zr : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω)) (w' : ValuesOn W (swigΩ Ω)) (ℓ : M'.LatentValues), h zr w' (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W)) ℓ) = M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk zr w') ℓ) : (fun w => condDistrib (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY) ∘ fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ((M'.fixSet Z hZ_obs hZ_fixed).evalMap (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t) ℓ)) (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ (fun _ hw => hZrW (mem_union_right _ hw))) ∘ fun ℓ : (M'.fixSet Z hZ_obs hZ_fixed).LatentValues => (M'.fixSet Z hZ_obs hZ_fixed).randomToObserved ((M'.fixSet Z hZ_obs hZ_fixed).evalMap (M'.fixSetExtend Z hZ_obs hZ_fixed s0 t) ℓ)) (M'.fixSet Z hZ_obs hZ_fixed).latentProduct w) =ᵐ[(M'.obsKernel s0).map (valuesProjection (fun _ hw => hZrW (mem_union_right _ hw)))] (fun w => ((condDistrib (valuesProjection (M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W))) (fun ℓ : M'.LatentValues => valuesProjection (fun _ hw => hZrW (mem_union_right _ hw)) (M'.randomToObserved (M'.evalMap s0 ℓ))) M'.latentProduct) w).map (h t w)) := by classical have hW : W ⊆ M'.observed := fun _ hw => hZrW (mem_union_right _ hw) set M2 := M'.fixSet Z hZ_obs hZ_fixed with hM2 set s' := M'.fixSetExtend Z hZ_obs hZ_fixed s0 t with hs' haveI : IsProbabilityMeasure M'.latentProduct := inferInstance haveI : IsFiniteMeasure M'.latentProduct := inferInstance set hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY with hhY_M2 set hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW with hhW_M2 set hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW with hhZrW_M2 -- The M2 / M1 observed-eval pullbacks. Both act on `M'.LatentValues = M2.LatentValues`. set E2 : M2.LatentValues → M2.ObservedValues := fun ℓ => M2.randomToObserved (M2.evalMap s' ℓ) with hE2_def set E1 : M'.LatentValues → M'.ObservedValues := fun ℓ => M'.randomToObserved (M'.evalMap s0 ℓ) with hE1_def -- Cut-set subset (the SAME finset on the M1 side; latent index spaces agree by `rfl`). have hCWsub : M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W) ⊆ M'.unobserved := M'.cutsetLatent_subset Y (Z.image SWIGNode.random ∪ W) -- (P2): the `W`-projection of `E2` equals that of `E1` (W non-descendant of the do-targets). have hP2 : ∀ ℓ : M2.LatentValues, valuesProjection hW_M2 (E2 ℓ) = valuesProjection hW (E1 ℓ) := by intro ℓ; funext v have hvW : v.val ∈ W := v.property have hvObs : v.val ∈ M'.observed := hW v.property have hkey := fixSet_evalMap_nonAnc_compat M' Z hZ_obs hZ_fixed s' ℓ (v := v.val) hvObs (fun z hz => hWNonDesc z hz v.val hvW) rw [M'.fixSetProj_fixSetExtend Z hZ_obs hZ_fixed s0 t] at hkey change M2.evalMap s' ℓ _ = M'.evalMap s0 _ _ rw [hkey]; rfl -- (P1): the `Y`-projection of `E2` is the M1 witness map at treatment `t`. -- Proof: M2's override at `Y` reduces — via `evalMap_overrideC_dropZr_on_fillZrW` and the -- cross-SCM compat `evalMap_overrideC_fixSet_compat_on_fillZrW` — to M1's override at the -- block value `valuesUnionMk t (π_W (E2 ℓ))`, which `hoverride` identifies with `h t ·`. have hP1 : ∀ ℓ : M2.LatentValues, valuesProjection hY_M2 (E2 ℓ) = h t (valuesProjection hW_M2 (E2 ℓ)) (valuesProjection hCWsub ℓ) := by intro ℓ -- Abbreviate the realized `W`-value of `E2 ℓ`. set w := valuesProjection hW_M2 (E2 ℓ) with hw_def -- (a) M2.evalMap_overrideC over `W` at its self-value equals `π_Y (E2 ℓ)`. have hself_W : (w : ValuesOn W (swigΩ Ω)) = (fun v' : {v // v ∈ W} => (M2.observedAt_observedIndex ⟨v'.val, hW_M2 v'.property⟩) ▸ evalObservedAux M2 s' ℓ (M2.observedIndex ⟨v'.val, hW_M2 v'.property⟩).val (M2.observedIndex ⟨v'.val, hW_M2 v'.property⟩).isLt) := by funext v' change (E2 ℓ) ⟨v'.val, hW_M2 v'.property⟩ = _ change M2.evalMap s' ℓ ⟨v'.val, _⟩ = _ rw [M2.evalMap_observed s' ℓ _ (hW_M2 v'.property)] have hcW : M2.evalMap_overrideC hY_M2 hW_M2 s' w ℓ = valuesProjection hY_M2 (E2 ℓ) := by rw [hself_W, M2.evalMap_overrideC_at_self hY_M2 hW_M2 s' ℓ] funext v change _ = (E2 ℓ) ⟨v.val, hY_M2 v.property⟩ change _ = M2.evalMap s' ℓ ⟨v.val, _⟩ rw [M2.evalMap_observed s' ℓ _ (hY_M2 v.property)] -- (b) override over `W` = override over `Zr∪W` at the `fillZrW`-filled block (`dropZr`). have hdrop : M2.evalMap_overrideC hY_M2 hZrW_M2 s' (M'.fillZrW Z hZ_obs hZ_fixed W s' w) ℓ = M2.evalMap_overrideC hY_M2 hW_M2 s' w ℓ := evalMap_overrideC_dropZr_on_fillZrW M' Z hZ_obs hZ_fixed Y W hY_M2 hZrW_M2 hDisj_YZr s' ℓ w -- (c) cross-SCM compat: M2 override over `Zr∪W` at `fillZrW` = M1 override over `Zr∪W` -- at `fillZrW`, base `fixSetProj s' = s0`, latent reindex = identity. have hcompat : M2.evalMap_overrideC hY_M2 hZrW_M2 s' (M'.fillZrW Z hZ_obs hZ_fixed W s' w) ℓ = M'.evalMap_overrideC hY hZrW s0 (valuesUnionMk t w) ℓ := by -- Rewrite the `M2`-side fill block to `valuesUnionMk t w` (`s' = fixSetExtend s0 t`). rw [hs', fillZrW_fixSetExtend M' Z hZ_obs hZ_fixed W s0 t w, ← hs'] funext v -- unfold both overrides to `evalObservedAuxOverride` at the SAME node `v.val`. rw [evalMap_overrideC_eq M2 hY_M2 hZrW_M2 s' _ ℓ v, evalMap_overrideC_eq M' hY hZrW s0 _ ℓ v] -- the compat lemma compares the full-observed-output overrides at node `v.val`; -- both unfold to the same `evalObservedAuxOverride` value, so transport via it. have hcv := evalMap_overrideC_fixSet_compat_on_fillZrW M' Z hZ_obs hZ_fixed W hZrW_M2 s' w ℓ (v := v.val) (hY_M2 v.property) -- `hcv` (read right→left) equates M2 and M1 full-output overrides at `⟨v.val, _⟩`. rw [evalMap_overrideC_eq M2 (refl _) hZrW_M2 s' _ ℓ ⟨v.val, hY_M2 v.property⟩, evalMap_overrideC_eq M' (refl _) hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s') _ _ ⟨v.val, hY v.property⟩] at hcv -- `s0 = fixSetProj s'`, `valuesUnionMk t w = fillZrW W s' w`, reindex ℓ = ℓ. rw [M'.fixSetProj_fixSetExtend Z hZ_obs hZ_fixed s0 t, fillZrW_fixSetExtend M' Z hZ_obs hZ_fixed W s0 t w] at hcv exact hcv.symm -- (d) `hoverride` identifies the M1 override at `(t, w)` with `h t w (π_{C_W} ℓ)`. rw [← hcW, ← hdrop, hcompat] exact (hoverride t w ℓ).symm -- Measurability of the M1 conditioning / cut-set maps (reuse the SCM helper). have hZmeas : Measurable (fun ℓ : M'.LatentValues => valuesProjection hW (E1 ℓ)) := M'.valuesProjection_randomToObserved_evalMap_meas hW s0 have hCmeas : Measurable (valuesProjection (Ω := swigΩ Ω) hCWsub) := measurable_valuesProjection hCWsub -- `H := fun w c => h t w c` packages the witness map at the fixed treatment `t`. have hH : Measurable (fun p : ValuesOn W (swigΩ Ω) × ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω) => h t p.1 p.2) := hh.comp (((measurable_const.prodMk measurable_fst).prodMk measurable_snd)) -- The no-treatment witness corollary on `M'.latentProduct`, conditioning on `π_W ∘ E1`. have hwit := condDistrib_map_of_funext (Ω := M'.LatentValues) (𝒵 := ValuesOn W (swigΩ Ω)) (𝒞 := ValuesOn (M'.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (swigΩ Ω)) (𝒴 := ValuesOn Y (swigΩ Ω)) M'.latentProduct (Z := fun ℓ : M'.LatentValues => valuesProjection hW (E1 ℓ)) (C := valuesProjection hCWsub) (H := fun w c => h t w c) hZmeas hCmeas hH -- The corollary's LHS factorized map `fun ℓ => h t (π_W (E1 ℓ)) (π_{C_W} ℓ)` equals `π_Y ∘ E2`. have hYeq : (fun ℓ : M'.LatentValues => h t (valuesProjection hW (E1 ℓ)) (valuesProjection hCWsub ℓ)) = fun ℓ : M2.LatentValues => valuesProjection hY_M2 (E2 ℓ) := by funext ℓ; rw [hP1 ℓ, hP2 ℓ] rw [hYeq] at hwit -- The base `M'.latentProduct.map (π_W ∘ E1)` equals `μW = (obsKernel s0).map π_W`. have hE1meas : Measurable (fun ℓ : M'.LatentValues => M'.randomToObserved (M'.evalMap s0 ℓ)) := M'.measurable_randomToObserved.comp (M'.evalMap_measurable.comp (measurable_const.prodMk measurable_id)) have hbaseμW : M'.latentProduct.map (fun ℓ : M'.LatentValues => valuesProjection hW (E1 ℓ)) = (M'.obsKernel s0).map (valuesProjection hW) := by rw [M'.obsKernel_eq_latentProduct_map s0, MeasureTheory.Measure.map_map (measurable_valuesProjection hW) hE1meas] rfl rw [hbaseμW] at hwit -- The goal's LHS conditioning map `π_W ∘ E2` equals `π_W ∘ E1` (by (P2)); rewrite `hwit`'s -- conditioning back to the `E2`-form so its LHS matches the goal's LHS (defeq otherwise). have hWmapeq : (fun ℓ : M2.LatentValues => valuesProjection hW_M2 (E2 ℓ)) = fun ℓ : M'.LatentValues => valuesProjection hW (E1 ℓ) := funext hP2 convert hwit using 3 congr 1
    Causalean.SCM.doSide_M2_pullback_eq_M1_witness · Causalean/SCM/Do/Rule2Kernel/WitnessBridge.lean:851
WMarginal 2 core · 4 supporting This file proves the filled-assignment measure identities used in the conditional version of Rule 2. ★ obsKernel_fixSet_W_marginal_pushforward_eq★ obsKernel_fixSet_W_rect_integral_eq

Marginal Identities for Rule 2

This file proves the filled-assignment measure identities used in the conditional version of Rule 2. The helper lemmas describe the image of a measurable W-event under fillZrW, prove that fillZrW is injective and a measurable embedding, and use that embedding in obsKernel_fixSet_W_marginal_pushforward_eq. The theorem obsKernel_fixSet_W_rect_integral_eq then gives the rectangle integral identity under the explicit hypothesis that the intervened random treatment copies equal their assigned fixed intervention values almost surely. These conditional identities are later upgraded to the full kernel statement of Rule 2.

lemma obsKernel_fixSet_W_marginal_pushforward_eq reviewed
Causalean.SCM

W-marginal pushforward identity. Fix a do-set Z of nodes whose random copies are observed in the base model and whose fixed nodes have not already been intervened on and an observation block W such that the union of Z's random copies and W is observed and disjoint from Z's random copies. If, under the intervened model's law of the observed variables given the fixed values s', the post-intervention random copies of Z almost surely equal their assigned intervention values, then for every measurable W-event A, the intervened model's marginal probability of A on W equals the base model's probability of the pullback of A through the map that fills in the pinned Z-random-copy coordinates alongside W.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
W :
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_ZrW :
Disjoint (Z.image SWIGNode.random) W
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s' :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
hPinned :
∀ᵐ ω ∂((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s'),
∀ D (hD : D ∈ Z),
ω ⟨SWIGNode.random D, hZ_obs D hD⟩
= s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩
A :
hA :
((map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ (by intro v hv exact hZrW (mem_union_right _ hv)))) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s'))) A
= ((map (valuesProjection hZrW) (M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s')))) ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A)
Proof (Lean source)
lemma obsKernel_fixSet_W_marginal_pushforward_eq (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (W : Finset (SWIGNode N)) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s' : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) (hPinned : ∀ᵐ ω ∂((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s'), ∀ D (hD : D ∈ Z), ω ⟨SWIGNode.random D, hZ_obs D hD⟩ = s' ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩) {A : Set (ValuesOn W (swigΩ Ω))} (hA : MeasurableSet A) : ((map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ (by intro v hv exact hZrW (mem_union_right _ hv)))) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s'))) A = ((map (valuesProjection hZrW) (M'.obsKernel (M'.fixSetProj Z hZ_obs hZ_fixed s')))) ((M'.fillZrW Z hZ_obs hZ_fixed W s') '' A) := by classical have hW : W ⊆ M'.observed := by intro v hv exact hZrW (mem_union_right _ hv) -- Abbreviations. let M2 := M'.fixSet Z hZ_obs hZ_fixed let sM1 : M'.FixedValues := M'.fixSetProj Z hZ_obs hZ_fixed s' let F := M'.fillZrW Z hZ_obs hZ_fixed W s' have hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW have hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW have hπW_M2 : Measurable (valuesProjection hW_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ have hπC_M1 : Measurable (valuesProjection hZrW : M'.ObservedValues → _) := measurable_valuesProjection _ have hImg_meas : MeasurableSet (F '' A) := measurableSet_fillZrW_image M' Z hZ_obs hZ_fixed W hDisj_ZrW s' hA -- Rewrite the maps as obsKernel applied to preimages. rw [MeasureTheory.Measure.map_apply hπW_M2 hA, MeasureTheory.Measure.map_apply hπC_M1 hImg_meas] -- Now: M2.obsKernel s' (π_W⁻¹ A) = M1.obsKernel sM1 (π_C⁻¹ (F''A)). -- Step 1: by (★), M2(π_W⁻¹A) = M2(π_W⁻¹A ∩ π_Zr⁻¹ {ζ_s}). -- We instead show that π_W⁻¹A = π_C⁻¹(F''A) ∪ N for a null set N under M2, -- and π_C⁻¹(F''A) ⊆ π_W⁻¹A. Then the measures are equal. -- Concrete plan: show that on the event {ω : π_Zr ω = ζ_s} (M2-a.e.), -- π_W ω ∈ A ↔ π_C ω ∈ F''A, -- so the two preimages agree M2-a.e. set ζ_s : ValuesOn (Z.image SWIGNode.random) (swigΩ Ω) := zFixedAsRandom (valuesProjection (fixSet_image_fixed_subset M' Z hZ_obs hZ_fixed) s') with hζ_def have hZr_subset : Z.image SWIGNode.random ⊆ M2.observed := by intro v hv exact hZrW_M2 (subset_union_left hv) have hImgExpand : F '' A = (fun c : ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω) => valuesProjection (Finset.subset_union_right (s₁ := Z.image SWIGNode.random)) c)⁻¹' A ∩ (fun c => valuesProjection (subset_union_left (s₂ := W)) c)⁻¹' ({ζ_s} : Set (ValuesOn (Z.image SWIGNode.random) (swigΩ Ω))) := fillZrW_image_eq M' Z hZ_obs hZ_fixed W hDisj_ZrW s' A -- Step A: apply Helper 1 with S := π_W⁻¹A to get -- M2(π_W⁻¹A ∩ π_C⁻¹(F''A)) = M1(π_W⁻¹A ∩ π_C⁻¹(F''A)) -- (where π_W⁻¹A on the M2 side uses hW_M2; same on M1 side with hW). -- But we want bare π_C⁻¹(F''A), so use S = univ. have hHelper1 : M2.obsKernel s' (univ ∩ (valuesProjection hZrW_M2)⁻¹' (F '' A)) = M'.obsKernel sM1 (univ ∩ (valuesProjection hZrW)⁻¹' (F '' A)) := obsKernel_inter_Wset_Zrand_levelset_eq M' Z hZ_obs hZ_fixed W hZrW hDisj_ZrW s' MeasurableSet.univ hA rw [Set.univ_inter, Set.univ_inter] at hHelper1 -- Now rewrite RHS = M1(π_C⁻¹(F''A)) using hHelper1 (reversed). rw [← hHelper1] -- Goal: M2.obsKernel s' (π_W⁻¹ A) = M2.obsKernel s' (π_C⁻¹ (F '' A)) -- where π_W uses hW_M2 and π_C uses hZrW_M2. -- Use the (★) hypothesis to show these sets agree M2-a.e. refine MeasureTheory.measure_congr ?_ refine Filter.Eventually.mono hPinned ?_ intro ω hω -- hω : ∀ D ∈ Z, ω ⟨.random D, hZ_obs D _⟩ = s' ⟨.fixed D, _⟩ -- Show: π_W⁻¹A ω ↔ π_C⁻¹(F''A) ω apply propext constructor · intro hπW_mem -- We have π_W ω ∈ A. Show π_C ω ∈ F''A by exhibiting `w = π_W ω`. change ω ∈ valuesProjection hZrW_M2 ⁻¹' (F '' A) refine ⟨valuesProjection hW_M2 ω, hπW_mem, ?_⟩ funext ⟨v, hv⟩ simp only [F, fillZrW] rcases Finset.mem_union.mp hv with hZrV | hWV · rw [valuesUnionMk_apply_left _ _ hZrV] obtain ⟨D, hDZ, hDeq⟩ := Finset.mem_image.mp hZrV cases hDeq simp only [zFixedAsRandom, valuesProjection] -- Goal: s' ⟨.fixed D, _⟩ = ω ⟨.random D, _⟩ (from valuesUnionMk_apply_left) exact (hω D hDZ).symm · by_cases hZrV' : v ∈ Z.image SWIGNode.random · rw [valuesUnionMk_apply_left _ _ hZrV'] obtain ⟨D, hDZ, hDeq⟩ := Finset.mem_image.mp hZrV' cases hDeq simp only [zFixedAsRandom, valuesProjection] exact (hω D hDZ).symm · rw [valuesUnionMk_apply_right _ _ _ hZrV'] simp only [valuesProjection] · intro hMem -- π_C ω = F w₀ for some w₀ ∈ A. Show π_W ω ∈ A. obtain ⟨w₀, hw₀A, hF_eq⟩ := hMem -- The W-coordinate of F w₀ equals w₀ (since W is disjoint from Z.image .random). suffices h : valuesProjection hW_M2 ω = w₀ by change ω ∈ valuesProjection hW_M2 ⁻¹' A rw [Set.mem_preimage, h]; exact hw₀A funext ⟨v, hvW⟩ have hv_in : v ∈ Z.image SWIGNode.random ∪ W := Finset.subset_union_right hvW have hvNotZr : v ∉ Z.image SWIGNode.random := fun hvZr => Finset.disjoint_left.mp hDisj_ZrW hvZr hvW have hcoord := congrFun hF_eq ⟨v, hv_in⟩ simp only [valuesProjection, F, fillZrW] at hcoord ⊢ rw [valuesUnionMk_apply_right _ _ hv_in hvNotZr] at hcoord exact hcoord.symm
theorem obsKernel_fixSet_W_rect_integral_eq reviewed
Causalean.SCM

Cross-SCM rectangle bridge for the W-marginal. Fix a do-set Z of nodes whose random copies are observed in the base model and whose fixed nodes have not already been intervened on, together with an outcome block Y and a conditioning block W of observed variables such that the union of Z's random copies and W is observed and disjoint from Z's random copies. Assume that, under the intervened model's law given the fixed values s, the post-intervention random copies of Z almost surely equal their assigned intervention values. Then for every measurable W-event A and every measurable Y-event B, integrating, over A and with respect to the intervened model's W-marginal, the base model's conditional probability of B given the outcome of filling in Z's pinned random-copy values alongside each w reconstructs the intervened model's probability that both the W-event A and the Y-event B occur.

Formal statement
M' :
SCM N Ω
Z :
hZ_obs :
∀ D ∈ Z, SWIGNode.random D ∈ M'.observed
hZ_fixed :
∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed
Y W :
hY :
Y ⊆ M'.observed
hW :
W ⊆ M'.observed
hZrW :
Z.image SWIGNode.random ∪ W ⊆ M'.observed
hDisj_ZrW :
Disjoint (Z.image SWIGNode.random) W
Nonempty (ValuesOn Y (swigΩ Ω))
CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))
s :
(M'.fixSet Z hZ_obs hZ_fixed).FixedValues
hPinned :
∀ᵐ ω ∂((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s),
∀ D (hD : D ∈ Z),
ω ⟨SWIGNode.random D, hZ_obs D hD⟩
= s ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩
A :
B :
hA :
hB :
∫⁻ w in A, (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B ∂(map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s))
= ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s) ((valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW))⁻¹' A ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY))⁻¹' B)
Proof (Lean source)
theorem obsKernel_fixSet_W_rect_integral_eq (M' : SCM N Ω) (Z : Finset N) (hZ_obs : ∀ D ∈ Z, SWIGNode.random D ∈ M'.observed) (hZ_fixed : ∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixed) (Y W : Finset (SWIGNode N)) (hY : Y ⊆ M'.observed) (hW : W ⊆ M'.observed) (hZrW : Z.image SWIGNode.random ∪ W ⊆ M'.observed) (hDisj_ZrW : Disjoint (Z.image SWIGNode.random) W) [StandardBorelSpace (ValuesOn Y (swigΩ Ω))] [Nonempty (ValuesOn Y (swigΩ Ω))] [CountableOrCountablyGenerated M'.FixedValues (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] [MeasurableSingletonClass (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω))] (s : (M'.fixSet Z hZ_obs hZ_fixed).FixedValues) (hPinned : ∀ᵐ ω ∂((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s), ∀ D (hD : D ∈ Z), ω ⟨SWIGNode.random D, hZ_obs D hD⟩ = s ⟨SWIGNode.fixed D, SCM.fixed_mem_fixSet M' Z hZ_obs hZ_fixed hD⟩) {A : Set (ValuesOn W (swigΩ Ω))} {B : Set (ValuesOn Y (swigΩ Ω))} (hA : MeasurableSet A) (hB : MeasurableSet B) : ∫⁻ w in A, (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (M'.fixSetProj Z hZ_obs hZ_fixed s, M'.fillZrW Z hZ_obs hZ_fixed W s w)) B ∂(map (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW)) ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s)) = ((M'.fixSet Z hZ_obs hZ_fixed).obsKernel s) ((valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW))⁻¹' A ∩ (valuesProjection ((fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY))⁻¹' B) := by -- ============================================================ -- Proof strategy (using the (★) hypothesis `hPinned`): -- -- Let M1 = M', M2 = M'.fixSet Z hZ_obs hZ_fixed, -- sM1 = M'.fixSetProj Z hZ_obs hZ_fixed s, -- F = fillZrW Z hZ_obs hZ_fixed W s. -- Let ν_W := (M2.obsKernel s).map π_W, μ_C := (M1.obsKernel sM1).map π_C. -- Let ĥ(c) := M1.obsCondKernel Y (Z.image .random ∪ W) (sM1, c) B. -- -- LHS = ∫⁻ w in A, ĥ(F w) d ν_W -- = ∫⁻ c in F''A, ĥ(c) d (ν_W.map F) [change of vars, F MeasEmb] -- = ∫⁻ c in F''A, ĥ(c) d (μ_C.restrict (range F))[ν_W = μ_C.comap F via helper] -- = ∫⁻ c in F''A, ĥ(c) d μ_C [F''A ⊆ range F] -- = M1.obsKernel sM1 (π_C⁻¹(F''A) ∩ π_Y⁻¹ B) [Helper 2 / M1 disintegration] -- = M2.obsKernel s (π_C⁻¹(F''A) ∩ π_Y⁻¹ B) [Helper 1, S := π_Y⁻¹B] -- = M2.obsKernel s (π_W⁻¹A ∩ π_Y⁻¹ B) [by (★) and hImg] -- = RHS. -- ============================================================ classical let M1 := M' let M2 := M'.fixSet Z hZ_obs hZ_fixed let sM1 : M1.FixedValues := M'.fixSetProj Z hZ_obs hZ_fixed s let F := M'.fillZrW Z hZ_obs hZ_fixed W s have hZrW_M2 : Z.image SWIGNode.random ∪ W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hZrW have hW_M2 : W ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hW have hY_M2 : Y ⊆ M2.observed := (fixSet_observed M' Z hZ_obs hZ_fixed).symm ▸ hY -- F is a MeasurableEmbedding. have hME : MeasurableEmbedding F := measurableEmbedding_fillZrW M' Z hZ_obs hZ_fixed W hDisj_ZrW s have hF_meas : Measurable F := M'.measurable_fillZrW Z hZ_obs hZ_fixed W s have hπW_M2 : Measurable (valuesProjection hW_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ have hπC_M1 : Measurable (valuesProjection hZrW : M1.ObservedValues → _) := measurable_valuesProjection _ have hπC_M2 : Measurable (valuesProjection hZrW_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ have hπY_M2 : Measurable (valuesProjection hY_M2 : M2.ObservedValues → _) := measurable_valuesProjection _ have hπY_M1 : Measurable (valuesProjection hY : M1.ObservedValues → _) := measurable_valuesProjection _ -- Abbreviations for measures and integrand. set ν_W : Measure (ValuesOn W (swigΩ Ω)) := (M2.obsKernel s).map (valuesProjection hW_M2) with hν_W_def set μ_C : Measure (ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω)) := (M1.obsKernel sM1).map (valuesProjection hZrW) with hμ_C_def let ĥ : ValuesOn (Z.image SWIGNode.random ∪ W) (swigΩ Ω) → ENNReal := fun c => (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (sM1, c)) B -- Image of A is measurable in `ValuesOn (Z.image .random ∪ W)`. have hImg_meas : MeasurableSet (F '' A) := hME.measurableSet_image' hA -- The pushforward identity from the helper. have hPushApply : ∀ ⦃S : Set (ValuesOn W (swigΩ Ω))⦄, MeasurableSet S → ν_W S = μ_C (F '' S) := by intro S hS simp only [hν_W_def, hμ_C_def] exact obsKernel_fixSet_W_marginal_pushforward_eq M' Z hZ_obs hZ_fixed W hZrW hDisj_ZrW s hPinned hS -- ν_W = μ_C.comap F as measures on `ValuesOn W`. have hcomap_eq : ν_W = μ_C.comap F := by refine MeasureTheory.Measure.ext ?_ intro S hS rw [hME.comap_apply, hPushApply hS] -- ν_W.map F = μ_C.restrict (range F). have hmap_F : ν_W.map F = μ_C.restrict (range F) := by rw [hcomap_eq, hME.map_comap] -- ---------------------------------------------------------------- -- Step 1: rewrite LHS using `MeasurableEmbedding.lintegral_map`. -- LHS = ∫⁻ c in F''A, ĥ(c) d (ν_W.map F). -- ---------------------------------------------------------------- -- The current LHS displays the measure as -- `Measure.map (valuesProjection ((fixSet_observed ...).symm ▸ hW)) (M2.obsKernel s)` -- which is definitionally equal to `ν_W`. Likewise the integrand is `ĥ ∘ F`. have hLHS_step1 : ∫⁻ w in A, (M'.obsCondKernel Y (Z.image SWIGNode.random ∪ W) hY hZrW (sM1, F w)) B ∂ν_W = ∫⁻ c in F '' A, ĥ c ∂(ν_W.map F) := by -- ∫⁻ c in F''A, ĥ c d (ν_W.map F) -- = ∫⁻ c, indicator(F''A) c · ĥ c d (ν_W.map F) -- = ∫⁻ w, indicator(F''A) (F w) · ĥ (F w) d ν_W [lintegral_map] -- = ∫⁻ w, indicator(A) w · ĥ (F w) d ν_W [F injective] -- = ∫⁻ w in A, ĥ (F w) d ν_W rw [← MeasureTheory.lintegral_indicator hImg_meas, hME.lintegral_map (fun c => (F '' A).indicator ĥ c), ← MeasureTheory.lintegral_indicator hA] refine MeasureTheory.lintegral_congr ?_ intro w by_cases hw : w ∈ A · have hFw : F w ∈ F '' A := ⟨w, hw, rfl⟩ simp [Set.indicator_of_mem hw, Set.indicator_of_mem hFw, ĥ] · have hFw : F w ∉ F '' A := by rintro ⟨w', hw', heq⟩ exact hw (hME.injective heq ▸ hw') simp [Set.indicator_of_notMem hw, Set.indicator_of_notMem hFw] -- ---------------------------------------------------------------- -- Step 2: ∫⁻ c in F''A, ĥ d (ν_W.map F) = ∫⁻ c in F''A, ĥ d μ_C -- using ν_W.map F = μ_C.restrict (range F) and F''A ⊆ range F. -- ---------------------------------------------------------------- have hRangeF : F '' A ⊆ range F := Set.image_subset_range _ _ have hLHS_step2 : ∫⁻ c in F '' A, ĥ c ∂(ν_W.map F) = ∫⁻ c in F '' A, ĥ c ∂μ_C := by rw [hmap_F] -- (μ_C.restrict (range F)).restrict (F''A) = μ_C.restrict ((F''A) ∩ range F) -- = μ_C.restrict (F''A) since F''A ⊆ range F. rw [MeasureTheory.Measure.restrict_restrict_of_subset hRangeF] -- ---------------------------------------------------------------- -- Step 3: ∫⁻ c in F''A, ĥ d μ_C = M1.obsKernel sM1 (π_C⁻¹ (F''A) ∩ π_Y⁻¹ B) -- via Helper 2 (M1 disintegration along π_C, CC := Z.image .random ∪ W). -- ---------------------------------------------------------------- have hLHS_step3 : ∫⁻ c in F '' A, ĥ c ∂μ_C = M1.obsKernel sM1 ((valuesProjection hZrW)⁻¹' (F '' A) ∩ (valuesProjection hY)⁻¹' B) := by rw [hμ_C_def] exact (obsKernel_disintegrate_rect M1 Y (Z.image SWIGNode.random ∪ W) hY hZrW sM1 hImg_meas hB).symm -- ---------------------------------------------------------------- -- Step 4: swap M1 to M2 using Helper 1 (S := π_Y⁻¹ B). -- ---------------------------------------------------------------- have hHelper1 : M2.obsKernel s ((valuesProjection hY_M2)⁻¹' B ∩ (valuesProjection hZrW_M2)⁻¹' (F '' A)) = M1.obsKernel sM1 ((valuesProjection hY)⁻¹' B ∩ (valuesProjection hZrW)⁻¹' (F '' A)) := obsKernel_inter_Wset_Zrand_levelset_eq M' Z hZ_obs hZ_fixed W hZrW hDisj_ZrW s (hπY_M1 hB) hA -- Both intersections appear in either order: align via Set.inter_comm. have hLHS_step4 : M1.obsKernel sM1 ((valuesProjection hZrW)⁻¹' (F '' A) ∩ (valuesProjection hY)⁻¹' B) = M2.obsKernel s ((valuesProjection hZrW_M2)⁻¹' (F '' A) ∩ (valuesProjection hY_M2)⁻¹' B) := by rw [Set.inter_comm ((valuesProjection hZrW)⁻¹' (F '' A)) ((valuesProjection hY)⁻¹' B), Set.inter_comm ((valuesProjection hZrW_M2)⁻¹' (F '' A)) ((valuesProjection hY_M2)⁻¹' B)] -- … truncated; follow the source link for the rest …
4 supporting declarations (lemmas, instances)