SCM.Do.Rule2Kernel.WitnessBridge
The analytic core of Rule 2 of the do-calculus for treatments with arbitrary (possibly continuous) values.
Cutset 1 core · 3 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. ★ cutset_condIndep_condDistrib
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:
* ProbabilityTheory.condDistrib_map (Mathlib): 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_fillZrW → evalMap_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).
For a finite structural causal model with measurable node-value spaces, outcome and conditioning node sets and a treatment-variable set, if the random treatment copies are observed, the conditioning nodes are observed, and the relevant cut-set is d-separated from treatment given the conditioning nodes, then at any fixed-node assignment, the cut-set's conditional distribution given treatment and conditioning agrees almost surely with its conditional distribution given the conditioning variables alone.
Formal statement
Proof (Lean source)
3 supporting declarations (lemmas, instances)
-
obsKernel_eq_latentProduct_maptheorem — obsKernel s is the latent product pushed through randomToObserved ∘ evalMap s.hypothesesconclusionM.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 fun_prop rw [obsKernel, ProbabilityTheory.Kernel.map_apply _ M.measurable_randomToObserved, jointKernel_apply_eq, MeasureTheory.Measure.map_map M.measurable_randomToObserved hev] rfl -
valuesProjection_randomToObserved_evalMap_meastheorem — 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 rewrites can name the composite.hypothesesconclusionMeasurable (fun ℓ : M.LatentValues => valuesProjection hY (M.randomToObserved (M.evalMap s ℓ)))Proof (Lean source)
@[fun_prop] 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 fun_prop exact (measurable_valuesProjection hY).comp (M.measurable_randomToObserved.comp hev) -
cutset_factor_pointwisetheorem — Cut-set factorization, pointwise, at the realized override.hypothesesN :sharedType u_1N → Type u_2M :SCM N Ω∀ n, Nonempty (Ω n)Z :Finset NhY :Y ⊆ M.observedhZrW :Z.image SWIGNode.random ∪ W ⊆ M.observeds :M.FixedValuesconclusionconclusion 1ℓ :M.LatentValuesvaluesProjection 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)) ℓ)conclusion 2h 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]
DoSide 3 core · 1 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. ★ 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:
* ProbabilityTheory.condDistrib_map (Mathlib): 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_fillZrW → evalMap_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).
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, and the union of the treatments' pre-intervention nodes 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, for every candidate treatment/W pair and latent cut-set value, returns the outcome obtained by 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
Proof (Lean source)
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, and the union of the treatments' pre-intervention nodes 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, for every candidate treatment/W pair and latent cut-set value, returns the outcome obtained by 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
Proof (Lean source)
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
Proof (Lean source)
1 supporting declaration (lemmas, instances)
-
doSide_M2_pullback_eq_M1_witnesstheorem — Do-side cross-SCM core: the M2-pullback W-conditional on M2.latentProduct equals the M1 posterior witness kernel.hypothesesN :sharedType u_1N → Type u_2M' :SCM N ΩZ :Finset NhZ_obs :∀ D ∈ Z, SWIGNode.random D ∈ M'.observedhZ_fixed :∀ D ∈ Z, SWIGNode.fixed D ∉ M'.fixedhY :Y ⊆ M'.observedhZrW :Z.image SWIGNode.random ∪ W ⊆ M'.observedhDisj_YZr :Disjoint Y (Z.image SWIGNode.random)hWNonDesc :∀ z ∈ Z, ∀ v ∈ W, ¬ (M'.fixSet Z hZ_obs hZ_fixed).dag.isAncestor (SWIGNode.fixed z) vStandardBorelSpace M'.RandomValuesStandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).RandomValuesStandardBorelSpace (M'.fixSet Z hZ_obs hZ_fixed).ObservedValuess0 :M'.FixedValuesh :hh :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') ℓconclusion(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 ℓ)) := by fun_prop have hCmeas : Measurable (valuesProjection (Ω := swigΩ Ω) hCWsub) := by fun_prop -- `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 ℓ)) := by fun_prop 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
ObsSide 1 core · 1 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
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:
* ProbabilityTheory.condDistrib_map (Mathlib): 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_fillZrW → evalMap_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).
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
Proof (Lean source)
1 supporting declaration (lemmas, instances)
-
obsCondKernel_union_eq_witnesstheorem — The (Zr∪W)-conditional packaged as the witness kernel.hypothesesN :sharedType u_1N → Type u_2M :SCM N ΩStandardBorelSpace M.RandomValues∀ n, StandardBorelSpace (swigΩ Ω n)∀ n, Nonempty (swigΩ Ω n)∀ s : M.FixedValues, IsFiniteMeasure (M.jointKernel s)Z :Finset NhY :Y ⊆ M.observedhZrW :Z.image SWIGNode.random ∪ W ⊆ M.observedhDisj_ZrW :Disjoint (Z.image SWIGNode.random) WhdSepCW :M.dag.dSep (M.cutsetLatent Y (Z.image SWIGNode.random ∪ W)) (Z.image SWIGNode.random) (W ∪ M.fixed)s :M.FixedValuesh :hh :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)) ℓ)conclusion(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 := by fun_prop have hπY : Measurable (valuesProjection (Ω := swigΩ Ω) hY) := by fun_prop have hπZrW : Measurable (valuesProjection (Ω := swigΩ Ω) hZrW) := by fun_prop -- 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 := ProbabilityTheory.condDistrib_map (ν := M.latentProduct) (f := E) hπZrW.aemeasurable hπY.aemeasurable hEmeas.aemeasurable rw [← MeasureTheory.Measure.map_map hπZrW hEmeas] at h2 -- 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