SCM.Factored

Factorization of an SCM's observational law into prefix kernels: parent lookup, step kernels, and the correspondence with deterministic evaluation.

Prefix­State 5 core · 2 supporting This file builds the finite prefix state spaces used to construct a structural causal model's joint kernel sequentially along a topological ordering. ★ measurable_extendOrderedLatentPrefix

Prefix States for Factored Kernels

This file builds the finite prefix state spaces used to construct a structural causal model's joint kernel sequentially along a topological ordering. The definitions package latent values together with already generated observed values, with measurability facts for the downstream factored-kernel construction.

def ObservedPrefixValues reviewed
Causalean.SCM

Values for the first n observed nodes in canonical topological order.

Definition (Lean source)
def ObservedPrefixValues (M : SCM N Ω) : (n : ℕ) → n ≤ M.observed.card → Type _ := fun n hn => match n with | 0 => PUnit.{uΩ + 1} | k + 1 => ObservedPrefixValues M k (le_of_succ_le hn) × swigΩ Ω (M.observedAt ⟨k, hn⟩).val
Causalean.SCM.ObservedPrefixValues · Causalean/SCM/Factored/PrefixState.lean:32 · uses SCM , SWIGNode
abbrev OrderedLatentPrefixValues reviewed
Causalean.SCM

Random values consisting of the latent tuple paired with an observed prefix. This is the state-space of the kernel at step n in the factored construction.

Definition (Lean source)
abbrev OrderedLatentPrefixValues (M : SCM N Ω) (n : ℕ) (hn : n ≤ M.observed.card) := LatentValues M × ObservedPrefixValues M n hn
Causalean.SCM.OrderedLatentPrefixValues · Causalean/SCM/Factored/PrefixState.lean:53 · uses SCM , SWIGNode
def observedPrefixValue reviewed
Causalean.SCM

Read the value of an observed node at position i < n from a prefix state of length n.

Definition (Lean source)
noncomputable def observedPrefixValue (M : SCM N Ω) : ∀ {n : ℕ} (hn : n ≤ M.observed.card), M.ObservedPrefixValues n hn → (i : Fin n) → swigΩ Ω (M.observedAt ⟨i.1, lt_of_lt_of_le i.2 hn⟩).val | 0, _, _, i => Fin.elim0 i | k + 1, hn, ξ, i => Fin.lastCases (by simpa using ξ.2) (fun j => by simpa using M.observedPrefixValue (le_of_succ_le hn) ξ.1 j) i
def extendOrderedLatentPrefix reviewed
Causalean.SCM

Append the next observed value to an ordered-latent prefix state. This is the state-space normalization map used after one compProd step in the factored construction: ((ℓ, ξ), y) ↦ (ℓ, (ξ, y)).

Definition (Lean source)
def extendOrderedLatentPrefix (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : (M.OrderedLatentPrefixValues n (le_of_succ_le hn) × swigΩ Ω (M.observedAt ⟨n, hn⟩).val) → M.OrderedLatentPrefixValues (n + 1) hn | ((ℓ, ξ), y) => (ℓ, (ξ, y))
theorem measurable_extendOrderedLatentPrefix reviewed
Causalean.SCM

Fix a structural causal model M and a step index n such that there are at least n + 1 observed nodes, so n names the next node to be appended in the canonical topological order of observed nodes. Then the map that appends the freshly generated value of that node to a length-n prefix of previously observed values, together with the latent assignment, producing a length-(n + 1) prefix, is measurable.

Formal statement
M :
SCM N Ω
n :
hn :
n + 1 ≤ M.observed.card
Measurable (M.extendOrderedLatentPrefix hn)
Proof (Lean source)
theorem measurable_extendOrderedLatentPrefix (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : Measurable (M.extendOrderedLatentPrefix hn) := prodMk (measurable_fst.comp measurable_fst) (prodMk (measurable_snd.comp measurable_fst) measurable_snd)
2 supporting declarations (lemmas, instances)
  • instMeasurableSpaceObservedPrefixValues instance — Measurable-space structure on ObservedPrefixValues, by the same recursion as the type itself.
    noncomputable instance instMeasurableSpaceObservedPrefixValues (M : SCM N Ω) : ∀ {n : ℕ} (hn : n ≤ M.observed.card), MeasurableSpace (M.ObservedPrefixValues n hn) | 0, _ => by dsimp [ObservedPrefixValues] infer_instance | k + 1, hn => by dsimp [ObservedPrefixValues] letI := instMeasurableSpaceObservedPrefixValues (M := M) (hn := le_of_succ_le hn) infer_instance
    Causalean.SCM.instMeasurableSpaceObservedPrefixValues · Causalean/SCM/Factored/PrefixState.lean:41
  • measurable_observedPrefixValue theorem — observedPrefixValue is measurable in its prefix-state argument.
    M :
    SCM N Ω
    ∀ {n : ℕ} (hn : n ≤ M.observed.card) (i : Fin n),
    Measurable (fun ξ : M.ObservedPrefixValues n hn => M.observedPrefixValue hn ξ i) | 0, _, i
    => Fin.elim0 i | k
    + 1, hn, i
    => Fin.lastCases (by have h : Measurable (fun ξ : M.ObservedPrefixValues k (le_of_succ_le hn) × swigΩ Ω (M.observedAt ⟨k, hn⟩).val => ξ.2) := measurable_snd simp only [SCM.observedPrefixValue, Fin.lastCases_last] exact h) (fun j => by have h : Measurable (fun ξ : M.ObservedPrefixValues k (le_of_succ_le hn) × swigΩ Ω (M.observedAt ⟨k, hn⟩).val => M.observedPrefixValue (le_of_succ_le hn) ξ.1 j) := (M.measurable_observedPrefixValue (le_of_succ_le hn) j).comp measurable_fst simp only [SCM.observedPrefixValue, Fin.lastCases_castSucc] exact h) i
    Proof (Lean source)
    theorem measurable_observedPrefixValue (M : SCM N Ω) : ∀ {n : ℕ} (hn : n ≤ M.observed.card) (i : Fin n), Measurable (fun ξ : M.ObservedPrefixValues n hn => M.observedPrefixValue hn ξ i) | 0, _, i => Fin.elim0 i | k + 1, hn, i => Fin.lastCases (by have h : Measurable (fun ξ : M.ObservedPrefixValues k (le_of_succ_le hn) × swigΩ Ω (M.observedAt ⟨k, hn⟩).val => ξ.2) := measurable_snd simp only [SCM.observedPrefixValue, Fin.lastCases_last] exact h) (fun j => by have h : Measurable (fun ξ : M.ObservedPrefixValues k (le_of_succ_le hn) × swigΩ Ω (M.observedAt ⟨k, hn⟩).val => M.observedPrefixValue (le_of_succ_le hn) ξ.1 j) := (M.measurable_observedPrefixValue (le_of_succ_le hn) j).comp measurable_fst simp only [SCM.observedPrefixValue, Fin.lastCases_castSucc] exact h) i
    Causalean.SCM.measurable_observedPrefixValue · Causalean/SCM/Factored/PrefixState.lean:78
Prefix­Kernel 3 core · 3 supporting This file constructs the prefix kernels that generate latent variables and then observed variables sequentially along a topological order.

Prefix Kernels for Sequential Factorization

This file constructs the prefix kernels that generate latent variables and then observed variables sequentially along a topological order. These kernels are the recursive components used to express the structural-model joint kernel as a Markov factorization, with Markov-kernel instances for the base and recursive cases.

def latentKernelOnFixed reviewed
Causalean.SCM

The latent product law as a kernel indexed by fixed values. Ignores the fixed input and always returns the product distribution latentProduct. Shorthand for readability of the recursion below.

Definition (Lean source)
noncomputable def latentKernelOnFixed (M : SCM N Ω) : Kernel M.FixedValues M.LatentValues := const _ M.latentProduct
def jointKernelPrefixZero reviewed
Causalean.SCM

Base case of the recursive prefix kernel: only the latent variables have been generated so far, paired with the trivial PUnit observed prefix.

Definition (Lean source)
noncomputable def jointKernelPrefixZero (M : SCM N Ω) : Kernel M.FixedValues (M.OrderedLatentPrefixValues 0 (zero_le _)) := M.latentKernelOnFixed.map (fun ℓ => (ℓ, (PUnit.unit : PUnit.{uΩ + 1})))
def jointKernelPrefix reviewed
Causalean.SCM

The prefix kernel at level n: sends fixed values s to the joint law of the latent tuple together with the values of the first n observed nodes, built by sequential compProd with the deterministic stepKernels.

Definition (Lean source)
noncomputable def jointKernelPrefix (M : SCM N Ω) : (n : ℕ) → (hn : n ≤ M.observed.card) → Kernel M.FixedValues (M.OrderedLatentPrefixValues n hn) | 0, _ => M.jointKernelPrefixZero | k + 1, hn => ((M.jointKernelPrefix k (le_of_succ_le hn)) ⊗ₖ (M.stepKernel hn)).map (M.extendOrderedLatentPrefix hn)
3 supporting declarations (lemmas, instances)
Step­Kernel 3 core · 1 supporting This file constructs the deterministic kernel that generates the next observed coordinate from its fixed, latent, and previously generated observed parents. ★ measurable_stepFun

Step Kernels for Observed Nodes

This file constructs the deterministic kernel that generates the next observed coordinate from its fixed, latent, and previously generated observed parents. The step kernels are the local transition pieces in the sequential factorization of the joint kernel, and their measurability follows from the parent-lookup map and the SCM structural-function measurability field.

def stepFun reviewed
Causalean.SCM

The deterministic assignment producing the value of the n-th observed node v_n = M.observedAt ⟨n, hn⟩ from the current prefix state (s, ℓ, ξ): assemble the parent tuple via parentValuesFromPrefix, then apply the structural function M.structFun v_n.

Definition (Lean source)
noncomputable def stepFun (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : (M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn)) → swigΩ Ω (M.observedAt ⟨n, hn⟩).val := fun sℓξ => M.structFun (M.observedAt ⟨n, hn⟩) (M.parentValuesFromPrefix hn sℓξ)
theorem measurable_stepFun reviewed
Causalean.SCM

Fix a structural causal model M and a step index n such that there are at least n + 1 observed nodes, so n names a valid position in the canonical topological order of observed nodes. Then the deterministic map stepFun, which produces the value of the n-th observed node by assembling its parent tuple from the fixed values, latent values, and previously generated observed prefix and applying the node's structural equation, is measurable.

Formal statement
M :
SCM N Ω
n :
hn :
n + 1 ≤ M.observed.card
Measurable (M.stepFun hn)
Proof (Lean source)
theorem measurable_stepFun (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : Measurable (M.stepFun hn) := (M.structFun_measurable (M.observedAt ⟨n, hn⟩)).comp (M.measurable_parentValuesFromPrefix hn)
def stepKernel reviewed
Causalean.SCM

The step kernel for the n-th observed node. Since structFun v_n is a deterministic measurable map, the kernel is Kernel.deterministic (stepFun hn): on input (s, ℓ, ξ) it returns Dirac (structFun v_n (Pa(v_n))).

Definition (Lean source)
noncomputable def stepKernel (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : Kernel (M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn)) (swigΩ Ω (M.observedAt ⟨n, hn⟩).val) := deterministic (M.stepFun hn) (M.measurable_stepFun hn)
1 supporting declaration (lemmas, instances)
Eval­Map­Correspond 2 core · 8 supporting This file relates the recursive prefix-kernel construction to the deterministic evaluation map of a structural causal model. ★ jointKernelPrefix_apply_eq

Correspondence Between Prefix Kernels and Evaluation

This file relates the recursive prefix-kernel construction to the deterministic evaluation map of a structural causal model. It defines the deterministic prefix state produced by fixed and latent assignments, proves its measurability and latent projection facts, proves coordinate agreement with evalObservedAux, and identifies each prefix kernel as the pushforward of the latent product through that deterministic prefix map.

def partialEvalMap reviewed
Causalean.SCM

Deterministic twin of jointKernelPrefix: produces the prefix state (ℓ, observed-prefix) at level n as a plain function. Its Dirac-pushforward equals jointKernelPrefix n hn (see jointKernelPrefix_apply_eq).

Definition (Lean source)
noncomputable def partialEvalMap (M : SCM N Ω) : (n : ℕ) → (hn : n ≤ M.observed.card) → FixedValues M → LatentValues M → OrderedLatentPrefixValues M n hn | 0, _, _, ℓ => (ℓ, (PUnit.unit : PUnit.{uΩ + 1})) | k + 1, hn, s, ℓ => let prev := M.partialEvalMap k (le_of_succ_le hn) s ℓ M.extendOrderedLatentPrefix hn (prev, M.stepFun hn (s, prev))
theorem jointKernelPrefix_apply_eq reviewed
Causalean.SCM

Main correspondence. For a structural causal model M, its length-n prefix kernel evaluated at a fixed assignment s equals the pushforward of the latent-value product measure through the deterministic partial evaluation map at s.

Formal statement
M :
SCM N Ω
s :
∀ (n : ℕ) (hn : n ≤ M.observed.card),
(M.jointKernelPrefix n hn) s
= M.latentProduct.map (fun ℓ => M.partialEvalMap n hn s ℓ) | 0, _ => by have hpair0 : Measurable (fun ℓ : LatentValues M => (ℓ, (PUnit.unit : PUnit.{uΩ + 1})))
Proof (Lean source)
theorem jointKernelPrefix_apply_eq (M : SCM N Ω) (s : FixedValues M) : ∀ (n : ℕ) (hn : n ≤ M.observed.card), (M.jointKernelPrefix n hn) s = M.latentProduct.map (fun ℓ => M.partialEvalMap n hn s ℓ) | 0, _ => by -- Base: jointKernelPrefixZero at `s` is `latentProduct.map (fun ℓ => (ℓ, PUnit.unit))`, -- which matches `partialEvalMap 0 _ s ℓ = (ℓ, PUnit.unit)` by definition. -- `partialEvalMap 0 _ s ℓ = (ℓ, PUnit.unit)`, matching the def of -- `jointKernelPrefixZero` after unfolding `Kernel.map_apply` + `const_apply`. have hpair0 : Measurable (fun ℓ : LatentValues M => (ℓ, (PUnit.unit : PUnit.{uΩ + 1}))) := by fun_prop change (M.latentKernelOnFixed.map (fun ℓ => (ℓ, (PUnit.unit : PUnit.{uΩ + 1})))) s = _ rw [ProbabilityTheory.Kernel.map_apply _ hpair0] unfold latentKernelOnFixed rw [ProbabilityTheory.Kernel.const_apply] rfl | k + 1, hn => by have ih := M.jointKernelPrefix_apply_eq s k (le_of_succ_le hn) -- Measurability helpers. have hext := M.measurable_extendOrderedLatentPrefix hn have hstep := M.measurable_stepFun hn have hpair : Measurable (fun ξ : M.OrderedLatentPrefixValues k (le_of_succ_le hn) => (ξ, M.stepFun hn (s, ξ))) := prodMk measurable_id (hstep.comp (prodMk measurable_const measurable_id)) have hpem : Measurable (fun ℓ : LatentValues M => M.partialEvalMap k (le_of_succ_le hn) s ℓ) := (M.measurable_partialEvalMap k (le_of_succ_le hn)).comp (prodMk measurable_const measurable_id) -- Unfold `jointKernelPrefix (k+1)` to `(compProd k ⊗ stepKernel).map extend`. change (((M.jointKernelPrefix k (le_of_succ_le hn)) ⊗ₖ (M.stepKernel hn)).map (M.extendOrderedLatentPrefix hn)) s = _ rw [ProbabilityTheory.Kernel.map_apply _ hext] -- Collapse the compProd with deterministic stepKernel via 3b helper. unfold stepKernel rw [compProd_deterministic_apply (M.jointKernelPrefix k (le_of_succ_le hn)) hstep s] -- LHS: `((κ s).map pair).map extend`. Compose via `Measure.map_map`. rw [MeasureTheory.Measure.map_map hext hpair] -- Apply IH to replace `κ s` with `latentProduct.map (partialEvalMap k _ s ·)`. rw [ih] -- LHS: `(latentProduct.map (partialEvalMap k _ s)).map (extend ∘ pair)`. -- Collapse via `Measure.map_map` once more. rw [MeasureTheory.Measure.map_map (hext.comp hpair) hpem] -- Match composition with `partialEvalMap (k+1) hn s ·` by definitional unfolding. rfl
8 supporting declarations (lemmas, instances)
  • partialEvalMap_latent theorem — The first component of partialEvalMap is always the input latent tuple: the recursion only writes to the ObservedPrefixValues factor.
    M :
    SCM N Ω
    s :
    :
    ∀ (n : ℕ) (hn : n ≤ M.observed.card),
    (M.partialEvalMap n hn s ℓ).1 = ℓ | 0, _ => rfl | k + 1, hn => by have ih
    Proof (Lean source)
    theorem partialEvalMap_latent (M : SCM N Ω) (s : FixedValues M) (ℓ : LatentValues M) : ∀ (n : ℕ) (hn : n ≤ M.observed.card), (M.partialEvalMap n hn s ℓ).1 = ℓ | 0, _ => rfl | k + 1, hn => by -- Unfold one step and reduce `extendOrderedLatentPrefix`. have ih := M.partialEvalMap_latent s ℓ k (le_of_succ_le hn) -- `partialEvalMap (k+1) hn s ℓ = extendOrderedLatentPrefix hn (prev, stepFun hn (s, prev))`. -- `extendOrderedLatentPrefix hn ((ℓ', ξ), y) = (ℓ', (ξ, y))`, so `.1 = prev.1 = ℓ` by IH. change (M.extendOrderedLatentPrefix hn (M.partialEvalMap k (le_of_succ_le hn) s ℓ, M.stepFun hn (s, M.partialEvalMap k (le_of_succ_le hn) s ℓ))).1 = ℓ -- By definition of `extendOrderedLatentPrefix` on `((ℓ', ξ), y)`. set prev := M.partialEvalMap k (le_of_succ_le hn) s ℓ with hprev rcases hprev_eq : prev with ⟨ℓ', ξ⟩ have : ℓ' = ℓ := by have : prev.1 = ℓ := ih rw [hprev_eq] at this exact this subst this rfl
    Causalean.SCM.partialEvalMap_latent · Causalean/SCM/Factored/EvalMapCorrespond.lean:80
  • measurable_partialEvalMap theorem — partialEvalMap is jointly measurable in (s, ℓ). Proved by induction on n: the base case is a product of projections, and the step case composes the measurable stepFun, extendOrderedLatentPrefix, and the inductive hypothesis.
    M :
    SCM N Ω
    ∀ (n : ℕ) (hn : n ≤ M.observed.card),
    Measurable (fun sℓ : FixedValues M × LatentValues M => M.partialEvalMap n hn sℓ.1 sℓ.2) | 0, _
    => by change Measurable (fun sℓ : FixedValues M × LatentValues M => (sℓ.2, (PUnit.unit : PUnit.{uΩ + 1}))) exact prodMk measurable_snd measurable_const | k
    + 1, hn => by have ih
    Proof (Lean source)
    theorem measurable_partialEvalMap (M : SCM N Ω) : ∀ (n : ℕ) (hn : n ≤ M.observed.card), Measurable (fun sℓ : FixedValues M × LatentValues M => M.partialEvalMap n hn sℓ.1 sℓ.2) | 0, _ => by -- `partialEvalMap 0 _ s ℓ = (ℓ, PUnit.unit)`. change Measurable (fun sℓ : FixedValues M × LatentValues M => (sℓ.2, (PUnit.unit : PUnit.{uΩ + 1}))) exact prodMk measurable_snd measurable_const | k + 1, hn => by have ih := M.measurable_partialEvalMap k (le_of_succ_le hn) -- Build the pair `(prev, stepFun hn (s, prev))`, then apply -- `extendOrderedLatentPrefix hn`. have hpair : Measurable (fun sℓ : FixedValues M × LatentValues M => (M.partialEvalMap k (le_of_succ_le hn) sℓ.1 sℓ.2, M.stepFun hn (sℓ.1, M.partialEvalMap k (le_of_succ_le hn) sℓ.1 sℓ.2))) := by refine prodMk ih ?_ refine (M.measurable_stepFun hn).comp ?_ exact prodMk measurable_fst ih exact (M.measurable_extendOrderedLatentPrefix hn).comp hpair
    Causalean.SCM.measurable_partialEvalMap · Causalean/SCM/Factored/EvalMapCorrespond.lean:109
  • compProd_deterministic_apply lemma — Composing a kernel with a deterministic second kernel gives the distribution obtained by drawing from the first kernel and appending the deterministic output to that draw. This map-valued identity is useful when constructing factored kernels recursively.
    κ :
    f :
    α × β → γ
    hf :
    a :
    α
    (κ ⊗ₖ deterministic f hf) a = (κ a).map (fun b => (b, f (a, b)))
    Proof (Lean source)
    lemma compProd_deterministic_apply {α β γ : Type*} [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] (κ : Kernel α β) [IsSFiniteKernel κ] {f : α × β → γ} (hf : Measurable f) (a : α) : (κ ⊗ₖ deterministic f hf) a = (κ a).map (fun b => (b, f (a, b))) := by have hpair : Measurable (fun b : β => (b, f (a, b))) := prodMk measurable_id (hf.comp (prodMk measurable_const measurable_id)) refine MeasureTheory.Measure.ext fun A hA => ?_ rw [ProbabilityTheory.Kernel.compProd_apply hA, MeasureTheory.Measure.map_apply hpair hA] simp only [ProbabilityTheory.Kernel.deterministic_apply] trans (∫⁻ b, indicator ((fun b => (b, f (a, b))) ⁻¹' A) (fun _ => (1 : ENNReal)) b ∂(κ a)) · apply MeasureTheory.lintegral_congr intro b have hSlice : MeasurableSet (Prod.mk b ⁻¹' A) := measurable_prodMk_left hA rw [MeasureTheory.Measure.dirac_apply' _ hSlice] simp only [indicator, Set.mem_preimage, Pi.one_apply] rfl · exact MeasureTheory.lintegral_indicator_one (hpair hA)
    Causalean.SCM.compProd_deterministic_apply · Causalean/SCM/Factored/EvalMapCorrespond.lean:140
  • observedPrefixValue_succ_last lemma — Appending an observed coordinate to a prefix makes the final coordinate of the expanded prefix equal to the appended value.
    M :
    SCM N Ω
    k :
    hn :
    k + 1 ≤ M.observed.card
    ξ :
    M.ObservedPrefixValues k (le_of_succ_le hn)
    y :
    swigΩ Ω (M.observedAt ⟨k, hn⟩).val
    M.observedPrefixValue hn ((ξ, y) : M.ObservedPrefixValues (k + 1) hn) (last k) = y
    Proof (Lean source)
    lemma observedPrefixValue_succ_last (M : SCM N Ω) {k : ℕ} (hn : k + 1 ≤ M.observed.card) (ξ : M.ObservedPrefixValues k (le_of_succ_le hn)) (y : swigΩ Ω (M.observedAt ⟨k, hn⟩).val) : M.observedPrefixValue hn ((ξ, y) : M.ObservedPrefixValues (k + 1) hn) (last k) = y := by simp [observedPrefixValue, Fin.lastCases_last]
    Causalean.SCM.observedPrefixValue_succ_last · Causalean/SCM/Factored/EvalMapCorrespond.lean:171
  • observedPrefixValue_succ_castSucc lemma — Appending an observed coordinate to a prefix leaves every earlier coordinate of the prefix unchanged.
    M :
    SCM N Ω
    k :
    hn :
    k + 1 ≤ M.observed.card
    ξ :
    M.ObservedPrefixValues k (le_of_succ_le hn)
    y :
    swigΩ Ω (M.observedAt ⟨k, hn⟩).val
    j :
    Fin k
    M.observedPrefixValue hn ((ξ, y) : M.ObservedPrefixValues (k + 1) hn) j.castSucc
    = M.observedPrefixValue (le_of_succ_le hn) ξ j
    Proof (Lean source)
    lemma observedPrefixValue_succ_castSucc (M : SCM N Ω) {k : ℕ} (hn : k + 1 ≤ M.observed.card) (ξ : M.ObservedPrefixValues k (le_of_succ_le hn)) (y : swigΩ Ω (M.observedAt ⟨k, hn⟩).val) (j : Fin k) : M.observedPrefixValue hn ((ξ, y) : M.ObservedPrefixValues (k + 1) hn) j.castSucc = M.observedPrefixValue (le_of_succ_le hn) ξ j := by simp [observedPrefixValue, Fin.lastCases_castSucc]
    Causalean.SCM.observedPrefixValue_succ_castSucc · Causalean/SCM/Factored/EvalMapCorrespond.lean:181
  • partialEvalMap_succ_snd_fst lemma — Extending a deterministic evaluation prefix by one observed variable leaves the previously computed observed prefix unchanged.
    M :
    SCM N Ω
    s :
    :
    k :
    hn :
    k + 1 ≤ M.observed.card
    ((M.partialEvalMap (k + 1) hn s ℓ).2 : M.ObservedPrefixValues (k + 1) hn).1
    = (M.partialEvalMap k (le_of_succ_le hn) s ℓ).2
    Proof (Lean source)
    lemma partialEvalMap_succ_snd_fst (M : SCM N Ω) (s : FixedValues M) (ℓ : LatentValues M) {k : ℕ} (hn : k + 1 ≤ M.observed.card) : ((M.partialEvalMap (k + 1) hn s ℓ).2 : M.ObservedPrefixValues (k + 1) hn).1 = (M.partialEvalMap k (le_of_succ_le hn) s ℓ).2 := by rfl
    Causalean.SCM.partialEvalMap_succ_snd_fst · Causalean/SCM/Factored/EvalMapCorrespond.lean:192
  • partialEvalMap_succ_snd_snd lemma — Extending a deterministic evaluation prefix appends the value determined for the newly added observed variable.
    M :
    SCM N Ω
    s :
    :
    k :
    hn :
    k + 1 ≤ M.observed.card
    ((M.partialEvalMap (k + 1) hn s ℓ).2 : M.ObservedPrefixValues (k + 1) hn).2
    = M.stepFun hn (s, M.partialEvalMap k (le_of_succ_le hn) s ℓ)
    Proof (Lean source)
    lemma partialEvalMap_succ_snd_snd (M : SCM N Ω) (s : FixedValues M) (ℓ : LatentValues M) {k : ℕ} (hn : k + 1 ≤ M.observed.card) : ((M.partialEvalMap (k + 1) hn s ℓ).2 : M.ObservedPrefixValues (k + 1) hn).2 = M.stepFun hn (s, M.partialEvalMap k (le_of_succ_le hn) s ℓ) := by rfl
    Causalean.SCM.partialEvalMap_succ_snd_snd · Causalean/SCM/Factored/EvalMapCorrespond.lean:202
  • partialEvalMap_observedPrefixValue theorem — Bridges partialEvalMap (kernel-side) to evalObservedAux (existing evaluator). Proven by induction on n mirroring the definitions: at each step, the newly-appended coordinate (index n) is stepFun hn (s, prev) = structFun v_n (parentValuesFromPrefix hn (s, prev)), which equals evalObservedAux M s ℓ n _ once one shows the parent lookups agree. Earlier indices are handled by the inductive hypothesis through observedPrefixValue of the extension.
    M :
    SCM N Ω
    s :
    :
    ∀ (n : ℕ) (hn : n ≤ M.observed.card) (i : Fin n)
    if
    M.observedPrefixValue hn (M.partialEvalMap n hn s ℓ).2 i
    = M.evalObservedAux s ℓ i.val (lt_of_lt_of_le i.isLt hn) | 0, _, i => Fin.elim0 i | k
    + 1, hn, i
    => by refine Fin.lastCases ?_ ?_ i · change M.observedPrefixValue hn ((M.partialEvalMap k (le_of_succ_le hn) s ℓ).2, M.stepFun hn (s, M.partialEvalMap k (le_of_succ_le hn) s ℓ)) (last k) = _ rw [observedPrefixValue_succ_last] unfold stepFun rw [evalObservedAux_eq] congr 1 funext w have hfix_disj_unobs : ∀ u : SWIGNode N, u ∈ M.unobserved
    then
    u ∉ M.fixed
    Proof (Lean source)
    theorem partialEvalMap_observedPrefixValue (M : SCM N Ω) (s : FixedValues M) (ℓ : LatentValues M) : ∀ (n : ℕ) (hn : n ≤ M.observed.card) (i : Fin n), M.observedPrefixValue hn (M.partialEvalMap n hn s ℓ).2 i = M.evalObservedAux s ℓ i.val (lt_of_lt_of_le i.isLt hn) | 0, _, i => Fin.elim0 i | k + 1, hn, i => by refine Fin.lastCases ?_ ?_ i · -- Last slot: i = last k. LHS reduces to stepFun; RHS is evalObservedAux at k. -- Step 1: unfold `(partialEvalMap (k+1) hn s ℓ).2` as a pair. change M.observedPrefixValue hn ((M.partialEvalMap k (le_of_succ_le hn) s ℓ).2, M.stepFun hn (s, M.partialEvalMap k (le_of_succ_le hn) s ℓ)) (last k) = _ -- Step 2: pick the `y` slot. rw [observedPrefixValue_succ_last] -- Step 3: unfold `stepFun` and `evalObservedAux_eq` on the RHS. unfold stepFun rw [evalObservedAux_eq] -- Step 4: the `structFun` head matches (both at `⟨k, hn⟩`); reduce to parent-arg eq. congr 1 funext w -- Step 5: split by the parent class (fixed / unobserved / observed) on both sides. have hfix_disj_unobs : ∀ u : SWIGNode N, u ∈ M.unobserved → u ∉ M.fixed := by intro u hu hf obtain ⟨m, hm⟩ := M.fixed_is_fixed u hf obtain ⟨j, hj⟩ := M.unobserved_is_random u hu rw [hm] at hj; cases hj simp only [parentValuesFromPrefix] by_cases hfix : w.val ∈ M.fixed · -- Fixed parent branch. simp only [dif_pos hfix] have huo : w.val ∉ M.unobserved := fun hu => hfix_disj_unobs _ hu hfix exact (parentMap_fixed M s ℓ _ _ w hfix).symm · simp only [dif_neg hfix] by_cases hobs : w.val ∈ M.observed · -- Observed parent branch: use IH on smaller prefix index. simp only [dif_pos hobs] have huo : w.val ∉ M.unobserved := not_unobs_of_obs M.toSWIGGraph hobs -- IH at (k, iobs) where iobs points to the parent's observed index. have hedge : M.dag.edge w.val (M.observedAt ⟨k, hn⟩).val := M.dag.mem_parents.mp w.property have hlt : M.observedIndex ⟨w.val, hobs⟩ < (⟨k, hn⟩ : Fin M.observed.card) := M.observed_parent_index_lt hn hedge hobs have hlt' : (M.observedIndex ⟨w.val, hobs⟩).val < k := hlt have ih := partialEvalMap_observedPrefixValue M s ℓ k (le_of_succ_le hn) ⟨(M.observedIndex ⟨w.val, hobs⟩).val, hlt'⟩ -- Rewrite `observedPrefixValue` via IH, so both sides become -- `castEq ▸ evalObservedAux s ℓ idx _` for the same equality. rw [ih] refine trans ?_ (parentMap_observed M s ℓ _ _ w hobs).symm -- Both sides transport the evaluator result along the same node -- equality. have hNode : (M.observedAt (M.observedIndex ⟨w.val, hobs⟩)).val = w.val := M.observedAt_observedIndex ⟨w.val, hobs⟩ simp [eqRec_eq_cast] · -- Unobserved parent branch. have hunobs : w.val ∈ M.unobserved := by have hedge : M.dag.edge w.val (M.observedAt ⟨k, hn⟩).val := M.dag.mem_parents.mp w.property have hclass : w.val ∈ M.fixed ∪ M.observed ∪ M.unobserved := (M.dag_edges_classified _ _ hedge).1 rcases Finset.mem_union.mp hclass with h | h · rcases Finset.mem_union.mp h with h | h · exact (hfix h).elim · exact (hobs h).elim · exact h simp only [dif_neg hobs] -- LHS: `sℓξ.2.1 ⟨w.val, hunobs⟩` where `sℓξ = (s, partialEvalMap k _ s ℓ)`, -- so `.2.1 = (partialEvalMap k _ s ℓ).1 = ℓ`. rw [partialEvalMap_latent] exact (parentMap_unobserved M s ℓ _ _ w hunobs).symm · -- Earlier slots: i = j.castSucc. Apply IH on (k, j). intro j have ih := partialEvalMap_observedPrefixValue M s ℓ k (le_of_succ_le hn) j -- Unfold `(partialEvalMap (k+1) hn s ℓ).2` as the pair `(prev.2, stepFun _)`, -- then use `observedPrefixValue_succ_castSucc` to recurse into `prev.2`. change M.observedPrefixValue hn ((M.partialEvalMap k (le_of_succ_le hn) s ℓ).2, M.stepFun hn (s, M.partialEvalMap k (le_of_succ_le hn) s ℓ)) j.castSucc = _ rw [observedPrefixValue_succ_castSucc] simpa using ih
    Causalean.SCM.partialEvalMap_observedPrefixValue · Causalean/SCM/Factored/EvalMapCorrespond.lean:216
Factorization 3 core · 2 supporting This file assembles the prefix-kernel correspondence into the final factorization theorem for the joint kernel of a structural causal model. ★ jointKernel_factored★ jointKernel_eq_factored_kernel

Factorization of the Joint Kernel

This file assembles the prefix-kernel correspondence into the final factorization theorem for the joint kernel of a structural causal model. It identifies the full prefix state with all random coordinates, proves the reindexing map is measurable, relates the full deterministic prefix map to evalMap, and states both pointwise and kernel-level factorization theorems.

def orderedLatentPrefixFullToRandom reviewed
Causalean.SCM

Reindex the full prefix state (all observed nodes generated, plus the latent tuple) to RandomValues M = ValuesOn (observed ∪ unobserved) (swigΩ Ω).

Definition (Lean source)
noncomputable def orderedLatentPrefixFullToRandom (M : SCM N Ω) : M.OrderedLatentPrefixValues M.observed.card (le_refl _) → M.RandomValues := fun p v => by by_cases hobs : v.val ∈ M.observed · have hEq : swigΩ Ω (M.observedAt (M.observedIndex ⟨v.val, hobs⟩)).val = swigΩ Ω v.val := by simpa using congrArg (swigΩ Ω) (M.observedAt_observedIndex ⟨v.val, hobs⟩) exact cast hEq (M.observedPrefixValue (le_refl _) p.2 (M.observedIndex ⟨v.val, hobs⟩)) · have hunobs : v.val ∈ M.unobserved := by rcases Finset.mem_union.mp v.property with hobs' | hunobs · exact elim (hobs hobs') · exact hunobs exact p.1 ⟨v.val, hunobs⟩
theorem jointKernel_factored reviewed
Causalean.SCM

Main factorization theorem (pointwise). For a structural causal model M, at each fixed assignment s, the joint kernel equals the pushforward of the full-length prefix kernel through the reindexing map identifying the full prefix state with the random coordinates.

Formal statement
M :
SCM N Ω
s :
M.jointKernel s
= ((M.jointKernelPrefix M.observed.card (le_refl _)) s).map M.orderedLatentPrefixFullToRandom
Proof (Lean source)
theorem jointKernel_factored (M : SCM N Ω) (s : FixedValues M) : M.jointKernel s = ((M.jointKernelPrefix M.observed.card (le_refl _)) s).map M.orderedLatentPrefixFullToRandom := by -- Step 1: unfold `jointKernel` at `s`. rw [M.jointKernel_apply_eq s] -- Step 2: rewrite `evalMap s` as `orderedLatentPrefixFullToRandompartialEvalMap _ _ s`. have hfun : (fun ℓ => M.evalMap s ℓ) = M.orderedLatentPrefixFullToRandom ∘ (fun ℓ => M.partialEvalMap M.observed.card (le_refl _) s ℓ) := by funext ℓ exact (M.partialEvalMap_full_eq s ℓ).symm rw [hfun] -- Step 3: use `Measure.map_map` to commute `.map` with composition. have hmeas_reindex := M.measurable_orderedLatentPrefixFullToRandom have hmeas_partial : Measurable (fun ℓ : LatentValues M => M.partialEvalMap M.observed.card (le_refl _) s ℓ) := by have := M.measurable_partialEvalMap M.observed.card (le_refl _) exact this.comp (prodMk measurable_const measurable_id) rw [← MeasureTheory.Measure.map_map hmeas_reindex hmeas_partial] -- Step 4: rewrite the inner `.map` using `jointKernelPrefix_apply_eq`. rw [← M.jointKernelPrefix_apply_eq s M.observed.card (le_refl _)]
theorem jointKernel_eq_factored_kernel reviewed
Causalean.SCM

Kernel-level factorization. For a structural causal model M, its joint kernel equals the prefix kernel at full length, pushed through the reindexing map identifying the full prefix state with the random coordinates. Follows from the pointwise form via kernel extensionality.

Formal statement
M :
SCM N Ω
M.jointKernel
= (M.jointKernelPrefix M.observed.card (le_refl _)).map M.orderedLatentPrefixFullToRandom
Proof (Lean source)
theorem jointKernel_eq_factored_kernel (M : SCM N Ω) : M.jointKernel = (M.jointKernelPrefix M.observed.card (le_refl _)).map M.orderedLatentPrefixFullToRandom := by refine ProbabilityTheory.Kernel.ext fun s => ?_ rw [ProbabilityTheory.Kernel.map_apply _ M.measurable_orderedLatentPrefixFullToRandom] exact M.jointKernel_factored s
2 supporting declarations (lemmas, instances)
  • measurable_orderedLatentPrefixFullToRandom theorem — orderedLatentPrefixFullToRandom is measurable. Case-split mirrors the definition; the observed branch composes observedPrefixValue with a cast.
    M :
    SCM N Ω
    Measurable M.orderedLatentPrefixFullToRandom
    Proof (Lean source)
    theorem measurable_orderedLatentPrefixFullToRandom (M : SCM N Ω) : Measurable M.orderedLatentPrefixFullToRandom := by classical refine measurable_pi_lambda _ ?_ intro ⟨n, hn⟩ simp only [orderedLatentPrefixFullToRandom] by_cases hobs : n ∈ M.observed · simp [hobs] have hNode : (M.observedAt (M.observedIndex ⟨n, hobs⟩)).val = n := M.observedAt_observedIndex ⟨n, hobs⟩ have hmeas : Measurable fun p : M.OrderedLatentPrefixValues M.observed.card (le_refl _) => M.observedPrefixValue (le_refl _) p.2 (M.observedIndex ⟨n, hobs⟩) := (M.measurable_observedPrefixValue (le_refl _) (M.observedIndex ⟨n, hobs⟩)).comp (measurable_snd : Measurable snd) exact (measurable_cast_family hNode).comp hmeas · have hunobs : n ∈ M.unobserved := by rcases Finset.mem_union.mp hn with hobs' | hunobs · exact elim (hobs hobs') · exact hunobs simp [hobs] exact ((measurable_pi_apply (⟨n, hunobs⟩ : {x // x ∈ M.unobserved})).comp (measurable_fst : Measurable fst))
    Causalean.SCM.measurable_orderedLatentPrefixFullToRandom · Causalean/SCM/Factored/Factorization.lean:78
  • partialEvalMap_full_eq theorem — Bridge lemma: reindexing the deterministic full-prefix value built from partialEvalMap at length observed.card yields exactly evalMap s ℓ.
    M :
    SCM N Ω
    s :
    :
    M.orderedLatentPrefixFullToRandom (M.partialEvalMap M.observed.card (le_refl _) s ℓ)
    = M.evalMap s ℓ
    Proof (Lean source)
    theorem partialEvalMap_full_eq (M : SCM N Ω) (s : FixedValues M) (ℓ : LatentValues M) : M.orderedLatentPrefixFullToRandom (M.partialEvalMap M.observed.card (le_refl _) s ℓ) = M.evalMap s ℓ := by funext v unfold orderedLatentPrefixFullToRandom by_cases hobs : v.val ∈ M.observed · -- Observed branch: both sides are (cast) of `evalObservedAux` at -- `observedIndex v`. simp only [hobs, dif_pos] -- LHS: cast hEq (observedPrefixValue ((partialEvalMap ...).2) (observedIndex v)) rw [M.partialEvalMap_observedPrefixValue s ℓ M.observed.card (le_refl _) (M.observedIndex ⟨v.val, hobs⟩)] -- RHS: evalMap_observed form rw [M.evalMap_observed s ℓ v hobs] -- Both sides transport the same `evalObservedAux` along the identity -- `(M.observedAt (observedIndex v)).val = v.val`. LHS uses `cast -- (congrArg (swigΩ Ω) h)`, RHS uses `h ▸ _`; they agree by the generic -- identity `cast (congrArg f h) x = h ▸ x` (both `mpr`/`mp` when -- `h` is used as a motive transport). -/ have hNode : (M.observedAt (M.observedIndex ⟨v.val, hobs⟩)).val = v.val := M.observedAt_observedIndex ⟨v.val, hobs⟩ -- Abstract the transported value as `aux` with the exact shape expected -- on the RHS: the `▸` motive transports along `hNode : (observedAt idx).val = v.val`, -- so `aux` must have type `swigΩ Ω (observedAt (observedIndex v)).val`. let aux0 : swigΩ Ω (M.observedAt (M.observedIndex ⟨v.val, hobs⟩)).val := M.evalObservedAux s ℓ (M.observedIndex ⟨v.val, hobs⟩).val (lt_of_lt_of_le (M.observedIndex ⟨v.val, hobs⟩).isLt (le_refl _)) -- Goal: cast hEq aux0 = hNode ▸ aux0; both transports use the same node -- equality, so they're equal via `eqRec_eq_cast`. change cast _ aux0 = hNode ▸ aux0 exact (eqRec_eq_cast (motive := fun x _ => swigΩ Ω x) aux0 hNode).symm · -- Unobserved branch: LHS reads `p.1 ⟨v.val, huo⟩ = ℓ ⟨v.val, huo⟩` by -- `partialEvalMap_latent`; RHS is `ℓ ⟨v.val, huo⟩` by `evalMap_unobserved`. simp only [hobs, dif_neg, not_false_eq_true] have hunobs : v.val ∈ M.unobserved := by rcases Finset.mem_union.mp v.property with hobs' | hunobs · exact elim (hobs hobs') · exact hunobs rw [M.evalMap_unobserved s ℓ v hunobs] -- LHS: `(partialEvalMap M.observed.card _ s ℓ).1 ⟨v.val, hunobs⟩` -- By `partialEvalMap_latent`, `.1 = ℓ`. have := M.partialEvalMap_latent s ℓ M.observed.card (le_refl _) rw [this]
    Causalean.SCM.partialEvalMap_full_eq · Causalean/SCM/Factored/Factorization.lean:109
Obs­Chain­Kernel 11 core · 25 supporting The observational kernel factors along the topological order of observed nodes as the iterated product of one-node conditional kernels given the full observed history. ★ obsKernel_eq_qFactorProduct

Observational Chain-Rule Kernel

The observational kernel factors along the topological order of observed nodes as the iterated product of one-node conditional kernels given the full observed history. This is the ordinary chain rule for kernels, formulated with Mathlib's continuous-safe condKernel.

This file builds the prefix node sets, the one-step observational conditional kernel, the recursive chain kernel, and the full-length product kernel qFactorProduct. The final equality with obsKernel is stated as the real kernel equality and proved by the standard disintegration induction.

def observedPredecessors reviewed
Causalean.SWIGGraph

Observed predecessors Pa⁺_G(v). The observed nodes appearing strictly before v in the topological order of G.dag.

Definition (Lean source)
noncomputable def observedPredecessors (v : SWIGNode N) : Finset (SWIGNode N) := G.observed.filter (fun w => G.dag.topoOrder w < G.dag.topoOrder v)
Causalean.SWIGGraph.observedPredecessors · Causalean/SCM/Factored/ObsChainKernel.lean:31 · uses SWIGGraph , SWIGNode
def prefixNodes reviewed
Causalean.SCM

The first n observed nodes in the canonical topological order. If n ≥ M.observed.card, this is all observed nodes.

Definition (Lean source)
noncomputable def prefixNodes (M : SCM N Ω) (n : ℕ) : Finset (SWIGNode N) := M.observed.filter (fun v => if h : v ∈ M.observed then (M.observedIndex ⟨v, h⟩).val < n else False)
def singletonValue reviewed
Causalean.SCM

Read the only coordinate of a singleton ValuesOn tuple.

Definition (Lean source)
noncomputable def singletonValue {ι : Type*} {α : ι → Type*} {v : ι} (x : ValuesOn ({v} : Finset ι) α) : α v := x ⟨v, by simp⟩
Causalean.SCM.singletonValue · Causalean/SCM/Factored/ObsChainKernel.lean:203 · uses ValuesOn
def singletonValues reviewed
Causalean.SCM

Build a singleton ValuesOn tuple from a value.

Definition (Lean source)
noncomputable def singletonValues {ι : Type*} {α : ι → Type*} {v : ι} (x : α v) : ValuesOn ({v} : Finset ι) α := fun ⟨w, hw⟩ => by have h : w = v := by simpa using hw exact h ▸ x
Causalean.SCM.singletonValues · Causalean/SCM/Factored/ObsChainKernel.lean:209 · uses ValuesOn
def obsStepCondKernel reviewed
Causalean.SCM

The single-node observational conditional kernel for the n-th observed node given the first n observed nodes.

Definition (Lean source)
noncomputable def obsStepCondKernel (M : SCM N Ω) {n : ℕ} (hn : n < M.observed.card) [StandardBorelSpace (ValuesOn ({(M.observedAt ⟨n, hn⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [Nonempty (ValuesOn ({(M.observedAt ⟨n, hn⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes n) (swigΩ Ω))] : Kernel (M.FixedValues × ValuesOn (M.prefixNodes n) (swigΩ Ω)) (swigΩ Ω (M.observedAt ⟨n, hn⟩).val) := (M.obsCondKernel ({(M.observedAt ⟨n, hn⟩).val} : Finset (SWIGNode N)) (M.prefixNodes n) (by intro v hv have hv_eq : v = (M.observedAt ⟨n, hn⟩).val := by simpa using hv simp [hv_eq, (M.observedAt ⟨n, hn⟩).property]) (M.prefixNodes_subset_observed n)).map (singletonValue (α := swigΩ Ω) (v := (M.observedAt ⟨n, hn⟩).val))
def emptyPrefixValues reviewed
Causalean.SCM

The unique value on the empty prefix.

Definition (Lean source)
noncomputable def emptyPrefixValues (M : SCM N Ω) : ValuesOn (M.prefixNodes 0) (swigΩ Ω) := fun ⟨v, hv⟩ => by have : v ∈ (∅ : Finset (SWIGNode N)) := by simp [M.prefixNodes_zero] at hv simp at this
def obsChainKernelZero reviewed
Causalean.SCM

The base observational chain kernel: a Dirac mass on the empty prefix.

Definition (Lean source)
noncomputable def obsChainKernelZero (M : SCM N Ω) : Kernel M.FixedValues (ValuesOn (M.prefixNodes 0) (swigΩ Ω)) := const _ (dirac M.emptyPrefixValues)
def extendObsPrefix reviewed
Causalean.SCM

Extend a prefix assignment by the next observed value.

Definition (Lean source)
noncomputable def extendObsPrefix (M : SCM N Ω) {n : ℕ} (hn : n < M.observed.card) : ValuesOn (M.prefixNodes n) (swigΩ Ω) × swigΩ Ω (M.observedAt ⟨n, hn⟩).val → ValuesOn (M.prefixNodes (n + 1)) (swigΩ Ω) := fun p => (valuesEquivOfEq (Ω := swigΩ Ω) (M.prefixNodes_succ hn).symm) (valuesUnionMk p.1 (singletonValues (α := swigΩ Ω) (v := (M.observedAt ⟨n, hn⟩).val) p.2))
def obsChainKernel reviewed
Causalean.SCM

The recursive observational chain-rule kernel through the first n observed nodes.

Definition (Lean source)
noncomputable def obsChainKernel (M : SCM N Ω) [∀ (k : ℕ) (hk : k < M.observed.card), StandardBorelSpace (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [∀ (k : ℕ) (hk : k < M.observed.card), Nonempty (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [∀ k : Fin M.observed.card, CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes k.val) (swigΩ Ω))] : (n : ℕ) → (hn : n ≤ M.observed.card) → Kernel M.FixedValues (ValuesOn (M.prefixNodes n) (swigΩ Ω)) | 0, _ => M.obsChainKernelZero | k + 1, hn => by have hk : k < M.observed.card := Nat.lt_of_succ_le hn letI : StandardBorelSpace (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω)) := inferInstance letI : Nonempty (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω)) := inferInstance letI : CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes k) (swigΩ Ω)) := (inferInstance : CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes (⟨k, hk⟩ : Fin M.observed.card).val) (swigΩ Ω))) exact ((M.obsChainKernel k (le_of_succ_le hn)) ⊗ₖ (M.obsStepCondKernel hk)).map (M.extendObsPrefix hk)
def qFactorProduct reviewed
Causalean.SCM

The full observational chain-rule product as a kernel on observed values.

Definition (Lean source)
noncomputable def qFactorProduct (M : SCM N Ω) [∀ (k : ℕ) (hk : k < M.observed.card), StandardBorelSpace (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [∀ (k : ℕ) (hk : k < M.observed.card), Nonempty (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [∀ k : Fin M.observed.card, CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes k.val) (swigΩ Ω))] : Kernel M.FixedValues M.ObservedValues := (M.obsChainKernel M.observed.card (le_refl _)).map (valuesEquivOfEq (Ω := swigΩ Ω) (M.prefixNodes_card M.observed.card (le_refl _)))
theorem obsKernel_eq_qFactorProduct reviewed
Causalean.SCM

For a structural causal model M, at a fixed assignment s, its observational kernel equals the full chain-rule product of one-node conditional kernels along the observed topological order.

Formal statement
M :
SCM N Ω
s :
M.FixedValues
∀ (k : ℕ) (hk : k < M.observed.card),
StandardBorelSpace (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))
∀ (k : ℕ) (hk : k < M.observed.card),
Nonempty (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))
∀ k :
Fin M.observed.card, CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes k.val) (swigΩ Ω))
M.obsKernel s = M.qFactorProduct s
Proof (Lean source)
theorem obsKernel_eq_qFactorProduct (M : SCM N Ω) (s : M.FixedValues) [∀ (k : ℕ) (hk : k < M.observed.card), StandardBorelSpace (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [∀ (k : ℕ) (hk : k < M.observed.card), Nonempty (ValuesOn ({(M.observedAt ⟨k, hk⟩).val} : Finset (SWIGNode N)) (swigΩ Ω))] [∀ k : Fin M.observed.card, CountableOrCountablyGenerated (M.FixedValues) (ValuesOn (M.prefixNodes k.val) (swigΩ Ω))] : M.obsKernel s = M.qFactorProduct s := by unfold qFactorProduct rw [ProbabilityTheory.Kernel.map_apply _ (valuesEquivOfEq (Ω := swigΩ Ω) (M.prefixNodes_card M.observed.card (le_refl _))).measurable] have hprefix := M.obsKernel_map_prefixNodes s M.observed.card (le_refl _) rw [← hprefix] rw [MeasureTheory.Measure.map_map (valuesEquivOfEq (Ω := swigΩ Ω) (M.prefixNodes_card M.observed.card (le_refl _))).measurable (measurable_valuesProjection (M.prefixNodes_subset_observed M.observed.card))] have hcomp : (valuesEquivOfEq (Ω := swigΩ Ω) (M.prefixNodes_card M.observed.card (le_refl _))) ∘ valuesProjection (M.prefixNodes_subset_observed M.observed.card) = (id : M.ObservedValues → M.ObservedValues) := by funext ω rfl rw [hcomp, MeasureTheory.Measure.map_id]
25 supporting declarations (lemmas, instances)
Parent­Lookup 2 core · 1 supporting This file builds the map that reads the parent values of the next observed node from a fixed assignment, a latent assignment, and an observed prefix. ★ measurable_parentValuesFromPrefix

Parent Lookup from Prefix States

This file builds the map that reads the parent values of the next observed node from a fixed assignment, a latent assignment, and an observed prefix. The lookup classifies each parent as fixed, observed, or unobserved, then proves the joint measurability needed by the deterministic step kernels in the factored construction of the joint kernel.

def parentValuesFromPrefix reviewed
Causalean.SCM

Assemble the full parent tuple of the next observed node v_n = M.observedAt ⟨n, hn⟩ from fixed values s, latent values , and the already-generated observed prefix ξ.

Definition (Lean source)
noncomputable def parentValuesFromPrefix (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : (M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn)) → (∀ w : {w // w ∈ M.dag.parents (M.observedAt ⟨n, hn⟩).val}, swigΩ Ω w.val) := fun sℓξ w => by by_cases hfix : w.val ∈ M.fixed · -- Fixed parent: read from `s = sℓξ.1`. exact sℓξ.1 ⟨w.val, hfix⟩ · by_cases hobs : w.val ∈ M.observed · -- Observed parent: read from the prefix `ξ = sℓξ.2.2` at index -- `observedIndex w < n`, then cast to `swigΩ Ω w.val`. have hlt : M.observedIndex ⟨w.val, hobs⟩ < ⟨n, hn⟩ := M.observed_parent_index_lt hn (M.dag.mem_parents.mp w.property) hobs let iobs : Fin n := ⟨(M.observedIndex ⟨w.val, hobs⟩ : ℕ), hlt⟩ have hEq : swigΩ Ω (M.observedAt (M.observedIndex ⟨w.val, hobs⟩)).val = swigΩ Ω w.val := by simpa using congrArg (swigΩ Ω) (M.observedAt_observedIndex ⟨w.val, hobs⟩) exact cast hEq <| by simpa [iobs] using M.observedPrefixValue (le_of_succ_le hn) sℓξ.2.2 iobs · -- Unobserved parent: read from `ℓ = sℓξ.2.1`. have hunobs : w.val ∈ M.unobserved := parent_unobserved_of_not_fixed_not_observed M.toSWIGGraph (M.dag.mem_parents.mp w.property) hfix hobs exact sℓξ.2.1 ⟨w.val, hunobs⟩
theorem measurable_parentValuesFromPrefix reviewed
Causalean.SCM

Fix a structural causal model M and a step index n such that there are at least n + 1 observed nodes, so n names a valid position in the canonical topological order of observed nodes. Then the map parentValuesFromPrefix that reads off the parent values of the n-th observed node from a fixed-value assignment, a latent assignment, and the already-generated length-n prefix of observed values is jointly measurable in these three arguments.

Formal statement
M :
SCM N Ω
n :
hn :
n + 1 ≤ M.observed.card
Measurable (M.parentValuesFromPrefix hn)
Proof (Lean source)
theorem measurable_parentValuesFromPrefix (M : SCM N Ω) {n : ℕ} (hn : n + 1 ≤ M.observed.card) : Measurable (M.parentValuesFromPrefix hn) := by classical refine measurable_pi_lambda _ ?_ intro w by_cases hfix : w.val ∈ M.fixed · -- Fixed case: projection `sℓξ ↦ sℓξ.1 ⟨w.val, hfix⟩`. have h0 : Measurable fun x : M.FixedValues => x (⟨w.val, hfix⟩ : {x // x ∈ M.fixed}) := measurable_pi_apply _ have h : Measurable fun c : M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn) => c.1 (⟨w.val, hfix⟩ : {x // x ∈ M.fixed}) := h0.comp measurable_fst simpa [SCM.parentValuesFromPrefix, hfix] using h · by_cases hobs : w.val ∈ M.observed · -- Observed case: `cast ∘ observedPrefixValue ∘ snd ∘ snd`. have hlt : M.observedIndex ⟨w.val, hobs⟩ < ⟨n, hn⟩ := M.observed_parent_index_lt hn (M.dag.mem_parents.mp w.property) hobs let iobs : Fin n := ⟨(M.observedIndex ⟨w.val, hobs⟩ : ℕ), hlt⟩ have hNode : (M.observedAt (M.observedIndex ⟨w.val, hobs⟩)).val = w.val := by simpa using M.observedAt_observedIndex ⟨w.val, hobs⟩ have hEq : swigΩ Ω (M.observedAt (M.observedIndex ⟨w.val, hobs⟩)).val = swigΩ Ω w.val := by simpa using congrArg (swigΩ Ω) hNode -- Measurability of reading slot `iobs` from the prefix, as a function -- of the full product input. have hmeas : Measurable fun c : M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn) => M.observedPrefixValue (le_of_succ_le hn) c.2.2 iobs := (M.measurable_observedPrefixValue (le_of_succ_le hn) iobs).comp ((measurable_snd : Measurable snd).comp (measurable_snd : Measurable snd)) have hcast : Measurable (fun y : swigΩ Ω (M.observedAt (M.observedIndex ⟨w.val, hobs⟩)).val => cast hEq y) := measurable_cast_family hNode have hmeasCast : Measurable fun c : M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn) => cast hEq (M.observedPrefixValue (le_of_succ_le hn) c.2.2 iobs) := hcast.comp hmeas simpa [SCM.parentValuesFromPrefix, hfix, hobs, iobs] using hmeasCast · -- Unobserved case: projection `sℓξ ↦ sℓξ.2.1 ⟨w.val, hunobs⟩`. have hunobs : w.val ∈ M.unobserved := parent_unobserved_of_not_fixed_not_observed M.toSWIGGraph (M.dag.mem_parents.mp w.property) hfix hobs have h0 : Measurable fun x : M.LatentValues => x (⟨w.val, hunobs⟩ : {x // x ∈ M.unobserved}) := measurable_pi_apply _ have h : Measurable fun c : M.FixedValues × M.OrderedLatentPrefixValues n (le_of_succ_le hn) => c.2.1 (⟨w.val, hunobs⟩ : {x // x ∈ M.unobserved}) := h0.comp (measurable_fst.comp measurable_snd) simpa [SCM.parentValuesFromPrefix, hfix, hobs, hunobs] using h
1 supporting declaration (lemmas, instances)
  • parent_unobserved_of_not_fixed_not_observed theorem — A parent that is neither fixed nor observed must be an unobserved node. This lets an evaluator classify a parent's value source without depending on where the target appears in an observation order.
    G :
    u v :
    hedge :
    G.dag.edge u v
    hfix :
    u ∉ G.fixed
    hobs :
    u ∉ G.observed
    u ∈ G.unobserved
    Proof (Lean source)
    theorem parent_unobserved_of_not_fixed_not_observed (G : SWIGGraph N) {u v : SWIGNode N} (hedge : G.dag.edge u v) (hfix : u ∉ G.fixed) (hobs : u ∉ G.observed) : u ∈ G.unobserved := by have hclass : u ∈ G.fixed ∪ G.observed ∪ G.unobserved := (G.dag_edges_classified _ _ hedge).1 rcases Finset.mem_union.mp hclass with h | h · rcases Finset.mem_union.mp h with h | h · exact (hfix h).elim · exact (hobs h).elim · exact h
    Causalean.SCM.parent_unobserved_of_not_fixed_not_observed · Causalean/SCM/Factored/ParentLookup.lean:57