A proof in src/Bluebell/ProbabilityTheory/Coupling.lean contains a sorry.
🤖 AI Analysis:
Statement Explanation
This theorem, Lift.graph, states that for any probability mass function (PMF) p on a type α and a deterministic function f : α → β, there exists a "lift" of p and p.map f to the relation defined by the graph of f.
Let's break down the components:
Lift p R q: This proposition is true if there exists a joint PMF c on α × β which is a "coupling" of p and q, and is "supported" on the relation R.
IsCoupling c p q: c is a coupling if its marginal distributions are p and q. This means if you sample from c and look only at the first component, you get the distribution p, and if you look at the second, you get q.
IsCoupling.supports c R: The support of c (the set of outcomes with non-zero probability) is a subset of R.
- The relation
{x : α × β | x.2 = f x.1} is the graph of the function f. It's the set of all pairs (a, b) where b = f a.
p.map f: This is the "pushforward" PMF on β, representing the distribution of f a where a is drawn from p.
The proof provides a witness for the coupling c, namely p.map (fun a => (a, f a)). This is the distribution of pairs (a, f a) where a is sampled from p.
The current proof obligation inside the refine is to prove that this witness is indeed a valid coupling, i.e., IsCoupling (p.map (fun a => (a, f a))) p (p.map f). The constructor tactic splits this into two goals:
- The first marginal of the coupling is
p.
- The second marginal of the coupling is
p.map f.
Context
This theorem provides a fundamental construction within the provided "Coupling API for program logics". The concept of "lifting" is central to relational verification of probabilistic programs, where one relates the distributions of variables in two different programs.
Lift.graph specifically handles deterministic computations. If a variable x has distribution p, and another variable y is computed as y := f x, this theorem formalizes the intuition that the joint distribution of (x, y) lives on the graph of f. The coupling p.map (fun a => (a, f a)) is often called the "graph coupling" and is a standard way to model this situation. This is a foundational lemma that will be used to build up more complex reasoning principles, such as Lift.bind.
Proof Suggestion
The constructor tactic has generated two goals. Both can be solved by reasoning about the composition of PMF.map.
-
First Goal: (p.map (fun a => (a, f a))).map Prod.fst = p
- This goal states that the first marginal of the proposed coupling is
p.
- Use the lemma
PMF.map_comp which says that mapping by g then h is the same as mapping by h ∘ g. Your expression has the form (p.map g).map h.
- Rewrite the left-hand side using
PMF.map_comp. It will become p.map (Prod.fst ∘ (fun a => (a, f a))).
- Now, simplify the function composition. The expression
Prod.fst (a, f a) simplifies to a, so the composed function is the identity function id. You can use the simp tactic for this.
- The goal will become
p.map id = p. This is true by the lemma PMF.map_id.
-
Second Goal: (p.map (fun a => (a, f a))).map Prod.snd = p.map f
- This goal states that the second marginal is
p.map f.
- The approach is identical to the first goal. Start by rewriting with
PMF.map_comp.
- The left-hand side will become
p.map (Prod.snd ∘ (fun a => (a, f a))).
- Simplify the composition.
Prod.snd (a, f a) simplifies to f a, so the composed function is f.
- The goal becomes
p.map f = p.map f, which is true by reflexivity (rfl).
You can likely solve both goals efficiently with a combination of rw [PMF.map_comp] and simp.
Goal: Replace the sorry with a complete proof.
Link to the sorry on GitHub
Code Snippet:
theorem Lift.graph (p : PMF α) (f : α → β) :
Lift p {x : α × β | x.2 = f x.1} (p.map f) := by
-- Use the image of `p` via pairing `(a, f a)` as a coupling witness.
-- Details deferred.
refine ⟨p.map (fun a => (a, f a)), ?_, ?_⟩
· constructor <;> sorry
A proof in
src/Bluebell/ProbabilityTheory/Coupling.leancontains asorry.🤖 AI Analysis:
Statement Explanation
This theorem,
Lift.graph, states that for any probability mass function (PMF)pon a typeαand a deterministic functionf : α → β, there exists a "lift" ofpandp.map fto the relation defined by the graph off.Let's break down the components:
Lift p R q: This proposition is true if there exists a joint PMFconα × βwhich is a "coupling" ofpandq, and is "supported" on the relationR.IsCoupling c p q:cis a coupling if its marginal distributions arepandq. This means if you sample fromcand look only at the first component, you get the distributionp, and if you look at the second, you getq.IsCoupling.supports c R: The support ofc(the set of outcomes with non-zero probability) is a subset ofR.{x : α × β | x.2 = f x.1}is the graph of the functionf. It's the set of all pairs(a, b)whereb = f a.p.map f: This is the "pushforward" PMF onβ, representing the distribution off awhereais drawn fromp.The proof provides a witness for the coupling
c, namelyp.map (fun a => (a, f a)). This is the distribution of pairs(a, f a)whereais sampled fromp.The current proof obligation inside the
refineis to prove that this witness is indeed a valid coupling, i.e.,IsCoupling (p.map (fun a => (a, f a))) p (p.map f). Theconstructortactic splits this into two goals:p.p.map f.Context
This theorem provides a fundamental construction within the provided "Coupling API for program logics". The concept of "lifting" is central to relational verification of probabilistic programs, where one relates the distributions of variables in two different programs.
Lift.graphspecifically handles deterministic computations. If a variablexhas distributionp, and another variableyis computed asy := f x, this theorem formalizes the intuition that the joint distribution of(x, y)lives on the graph off. The couplingp.map (fun a => (a, f a))is often called the "graph coupling" and is a standard way to model this situation. This is a foundational lemma that will be used to build up more complex reasoning principles, such asLift.bind.Proof Suggestion
The
constructortactic has generated two goals. Both can be solved by reasoning about the composition ofPMF.map.First Goal:
(p.map (fun a => (a, f a))).map Prod.fst = pp.PMF.map_compwhich says that mapping bygthenhis the same as mapping byh ∘ g. Your expression has the form(p.map g).map h.PMF.map_comp. It will becomep.map (Prod.fst ∘ (fun a => (a, f a))).Prod.fst (a, f a)simplifies toa, so the composed function is the identity functionid. You can use thesimptactic for this.p.map id = p. This is true by the lemmaPMF.map_id.Second Goal:
(p.map (fun a => (a, f a))).map Prod.snd = p.map fp.map f.PMF.map_comp.p.map (Prod.snd ∘ (fun a => (a, f a))).Prod.snd (a, f a)simplifies tof a, so the composed function isf.p.map f = p.map f, which is true by reflexivity (rfl).You can likely solve both goals efficiently with a combination of
rw [PMF.map_comp]andsimp.Goal: Replace the
sorrywith a complete proof.Link to the sorry on GitHub
Code Snippet: