Documentation

Linglib.Semantics.Causation.CausalModel.Defs

Causal models #

This file defines causal models in the sense of Halpern and Pearl. A causal model has a type U of exogenous contexts, a value type α v for each endogenous variable v, a directed graph on the variables (mathlib's Digraph), and for each variable a structural equation that gives its value from the context and the values of its parents in the graph. An intervention holds some variables at fixed values, and the others obey their equations (CausalModel.step). When the graph is well founded, every context and every intervention determine exactly one assignment that satisfies the equations, CausalModel.solve.

The solution is characterized as the unique fixed point of step, and it is reached by iterating step from any assignment once per rank of a ranking of the graph, which is how a finite model computes it.

Main definitions #

Main results #

Implementation notes #

An equation reads the whole assignment, and dependsOn_eqn says that it only reads the parents (mathlib's DependsOn), so equations are written without the parents' subtype. For a finite inductive type of variables the default proof of dependsOn_eqn discharges it. The graph is data, the edges a paper draws, and bounds what an equation may read rather than recording what it does read. An intervention is a partial assignment ∀ v, Flat (α v), the variables it settles being the intervened ones. The solution is WellFounded.fixedPoint of step, whose construction fills the coordinates an equation ignores arbitrarily, hence [∀ v, Nonempty (α v)].

A concrete model in a study is written to one recipe. The exogenous context is a structure whose fields name what the paper leaves to the world (structure Context where match : Bool, with deriving DecidableEq, Fintype, Inhabited, Repr), never a positional tuple. The edges are a Finset (V × V) (def edges : Finset (V × V) := {(.match, .fire)}) with graph := ⟨fun w v ↦ (w, v) ∈ edges⟩, adjacency is decided by fun w v ↦ inferInstanceAs (Decidable ((w, v) ∈ edges)), and acyclicity by Finite.wellFounded_of_irrefl_transGen (by decide). Partial assignments are written in the scoped notation, [c ← x, d ← y], and updates of a named assignment as Function.update s c ↑x. A theorem quantifying over assignments or settlements (necessity, sufficient sets) is proved structurally through the equations rather than by decide, which enumerates them.

References #

structure CausalModel (U : Type u_1) (V : Type u_2) (α : V → Type u_3) :
Type (max (max u_1 u_2) u_3)

A causal model is a directed graph on the variables V with a structural equation at each variable. The equation gives the variable's value in α v from an exogenous context in U and the values of the variable's parents, the sources of its incoming edges.

  • graph : Digraph V

    The causal graph, with an edge from w to v when v's equation may read w.

  • eqn (v : V) : U → ((w : V) → α w) → α v

    The structural equation of each variable, read in a context.

  • dependsOn_eqn (v : V) (u : U) : DependsOn (self.eqn v u) {w : V | self.graph.Adj w v}

    Each equation reads only the variable's parents. For a finite inductive type of variables whose equations match on the variable, the default proof rewrites each variable an equation reads by the hypothesis, deciding that it is a parent.

Instances For
    @[reducible, inline]
    abbrev CausalModel.IsAcyclic {U : Type u_1} {V : Type u_2} {α : V → Type u_3} (M : CausalModel U V α) :

    A model is acyclic, or recursive, when its graph is well founded.

    Equations
    Instances For
      class CausalModel.ContextAtRoots {U : Type u_1} {V : Type u_2} {α : V → Type u_3} (M : CausalModel U V α) :

      The context reaches a model only at its roots when the equation of every variable with a parent gives the same value in every context, as in the dynamics of Schulz and Nadathur, whose inner variables are truth functions of their parents.

      • eqn_eq_of_adj {v w : V} : M.graph.Adj w v → ∀ (u u' : U) (y : (w : V) → α w), M.eqn v u y = M.eqn v u' y
      Instances
        theorem CausalModel.IsAcyclic.of_depth {U : Type u_1} {V : Type u_2} {α : V → Type u_3} (M : CausalModel U V α) (depth : V → ℕ) (h : ∀ {w v : V}, M.graph.Adj w v → depth w < depth v) :

        A model is acyclic when every edge climbs in depth.

        def CausalModel.partialAssignment :
        Lean.ParserDescr

        [c ← x] is the partial assignment settling c to x and leaving every other variable open, in the notation of Halpern and Pearl; [c ← x, d ← y] settles both. It serves as an intervention and as an observation.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          def CausalModel.step {U : Type u_1} {V : Type u_2} {α : V → Type u_3} (M : CausalModel U V α) (I : (v : V) → Flat (α v)) (u : U) (x : (v : V) → α v) (v : V) :
          α v

          M.step I u x applies the equations once in the context u. A variable the intervention I settles takes its intervened value, and any other variable takes the value its equation gives to x.

          Equations
          Instances For
            theorem CausalModel.step_apply {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} (I : (v : V) → Flat (α v)) (u : U) (x : (v : V) → α v) (v : V) :
            M.step I u x v = Flat.unbotD (M.eqn v u x) (I v)
            theorem CausalModel.dependsOn_step {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} (I : (v : V) → Flat (α v)) (u : U) (v : V) :
            DependsOn (fun (x : (i : V) → α i) => M.step I u x v) {w : V | M.graph.Adj w v}

            Each round computes a variable from its parents.

            theorem CausalModel.iterate_step_apply_eq {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} (r : M.graph.Adj →r fun (x1 x2 : ℕ) => x1 < x2) (I : (v : V) → Flat (α v)) (u : U) {k : ℕ} {v : V} (hv : r v < k) (x y : (v : V) → α v) :
            (M.step I u)^[k] x v = (M.step I u)^[k] y v

            After k rounds of the equations, a variable of rank below k no longer depends on the assignment the rounds started from.

            noncomputable def CausalModel.solve {U : Type u_1} {V : Type u_2} {α : V → Type u_3} (M : CausalModel U V α) [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] (I : (v : V) → Flat (α v)) (u : U) (v : V) :
            α v

            The solution of the model under the intervention I in the context u, the unique fixed point of step.

            Equations
            Instances For
              theorem CausalModel.isFixedPt_solve {U : Type u_1} {V : Type u_2} {α : V → Type u_3} (M : CausalModel U V α) [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] (I : (v : V) → Flat (α v)) (u : U) :
              Function.IsFixedPt (M.step I u) (M.solve I u)

              The solution satisfies the equations.

              theorem CausalModel.eq_solve_of_isFixedPt {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] {I : (v : V) → Flat (α v)} {u : U} {x : (v : V) → α v} (hx : Function.IsFixedPt (M.step I u) x) :
              x = M.solve I u

              An assignment satisfying the equations is the solution.

              theorem CausalModel.isFixedPt_iff_eq_solve {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] {I : (v : V) → Flat (α v)} {u : U} {x : (v : V) → α v} :
              Function.IsFixedPt (M.step I u) x ↔ x = M.solve I u
              theorem CausalModel.solve_apply {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] (I : (v : V) → Flat (α v)) (u : U) (v : V) :
              M.solve I u v = Flat.unbotD (M.eqn v u (M.solve I u)) (I v)
              theorem CausalModel.solve_of_eq_coe {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] {I : (v : V) → Flat (α v)} {v : V} {x : α v} (h : I v = ↑x) (u : U) :
              M.solve I u v = x

              An intervened variable takes its intervened value.

              theorem CausalModel.solve_of_eq_bot {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] {I : (v : V) → Flat (α v)} {v : V} (h : I v = ⊥) (u : U) :
              M.solve I u v = M.eqn v u (M.solve I u)

              A variable the intervention leaves alone obeys its equation.

              theorem CausalModel.solve_eq_iterate {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] (r : M.graph.Adj →r fun (x1 x2 : ℕ) => x1 < x2) {n : ℕ} (hn : ∀ (v : V), r v < n) (I : (v : V) → Flat (α v)) (u : U) (x : (v : V) → α v) :
              M.solve I u = (M.step I u)^[n] x

              Iterating the equations from any assignment past a ranking of the graph reaches the solution.

              theorem CausalModel.solve_eq_iterate_card {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] [Fintype V] (I : (v : V) → Flat (α v)) (u : U) (x : (v : V) → α v) :
              M.solve I u = (M.step I u)^[Fintype.card V] x

              In a finite model, iterating the equations once per variable reaches the solution.

              @[instance_reducible, instance 10000]
              instance CausalModel.decidableEqSolve {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] [Fintype V] [(v : V) → Inhabited (α v)] [(v : V) → DecidableEq (α v)] (I : (v : V) → Flat (α v)) (u : U) (v : V) (x : α v) :
              Decidable (M.solve I u v = x)

              In a finite model the value of the solution at a variable is decided by iterating the equations. It takes priority over the value type's own decidable equality, which cannot evaluate solve.

              Equations
              @[instance_reducible, instance 10001]
              instance CausalModel.decidableEqSolveSolve {U : Type u_1} {V : Type u_2} {α : V → Type u_3} {M : CausalModel U V α} [∀ (v : V), Nonempty (α v)] [hM : M.IsAcyclic] [Fintype V] [(v : V) → Inhabited (α v)] [(v : V) → DecidableEq (α v)] (I J : (v : V) → Flat (α v)) (u u' : U) (v : V) :
              Decidable (M.solve I u v = M.solve J u' v)

              In a finite model, whether two solutions agree at a variable is decided by iterating the equations for both.

              Equations