diff --git a/DESIGN.md b/DESIGN.md index afa954a..67b5e19 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -59,6 +59,17 @@ Following Iris, specifications are stated with a weakest-precondition predicate that the initial and final distributions refine (`Framed`): the part of the state that satisfies the invariant is any space `𝓙` with `⌈IβŒ‰ 𝓙`, as in `P ⊨ Ο† βˆ— ⌈IβŒ‰`. +The paper runs programs on memories with a fixed domain. Here memories are partial, so +`wp` states two facts that the paper gets for free: + +- the postcondition space owns no variables beyond those of the precondition space + (`𝓠.dom βŠ† π“Ÿ.dom`); this is what makes the postconditions of two parallel threads + independent; +- the program does not deallocate variables (`Distr.Keeps ΞΌ Ξ½`: every variable that is + allocated in all initial memories is allocated in all final memories). The postcondition + space may be smaller than the precondition space, so without this fact the branches of an + outcome conjunction could not be brought back to a common domain (`Split`). + ## Invariants Invariants are ordered by factorization (`Inv.LE_Inv`): `π“˜ ≀ 𝓙` when `π“˜` is `𝓙 βˆ— π“š` for diff --git a/PcolIris/Examples/VonNeumann.lean b/PcolIris/Examples/VonNeumann.lean index 6247bf6..6507119 100644 --- a/PcolIris/Examples/VonNeumann.lean +++ b/PcolIris/Examples/VonNeumann.lean @@ -341,8 +341,17 @@ same defect that the development itself documents for `sum_prod_distribute`. -/ /-- **Introduction of a nondeterministic choice**: every branch of a nondeterministic choice entails the choice itself. (In the semantics of the paper `&` is a union of sets of probability spaces, so this is immediate.) -/ -lemma nondet_intro {iota : Type} [Countable iota] {phi : iota β†’ OProp} (i : iota) : phi i ⊒ OProp.nondet phi := - sorry +lemma nondet_intro {iota : Type} [Countable iota] {phi : iota β†’ OProp} (i : iota) : + phi i ⊒ OProp.nondet phi := by + intro π“Ÿ h + obtain ⟨code, hcode⟩ := Countable.exists_injective_nat iota + refine ⟨PMF.pure i, fun v ↦ π“Ÿ.shift (code v), π“Ÿ.dom, + fun hij ↦ ProbSpace.disjoint_support_shift _ _ (hcode.ne hij), fun _ ↦ rfl, ?_, ?_⟩ + Β· exact (ProbSpace.sum_pure_le _ _ i).trans (ProbSpace.shift_le _ _) + Β· intro v hv + rw [PMF.support_pure, Set.mem_singleton_iff] at hv + subst hv + exact (phi v).mono (ProbSpace.le_shift _ _) h /-- Nondeterministic choices are convex: a mixture of unions of mixtures is again one. -/ lemma Convex.nondet {iota : Type} [Countable iota] {phi : iota β†’ OProp} : Convex (OProp.nondet phi) := sorry @@ -551,7 +560,11 @@ lemma wp_body_nondet {L : Finset β„š} {F : ProbSpace β†’ Prop} (eps : β„š) the loop body. -/ lemma phi1_split : phi1 ⊒ iprop(⌈own ($"p'")βŒ‰ βˆ— (⌈own ($"x")βŒ‰ βˆ— ⌈own ($"y")βŒ‰)) := Iris.BI.Entails.trans (OProp.sure_weaken phi1_resources) - (Iris.BI.Entails.trans OProp.sure_sep.1 (Iris.BI.sep_mono_right OProp.sure_sep.1)) + (Iris.BI.Entails.trans + (OProp.sure_sep (MProp.Footprint.own_var _) + ((MProp.Footprint.own_var _).sep (MProp.Footprint.own_var _) (by simp))).1 + (Iris.BI.sep_mono_right + (OProp.sure_sep (MProp.Footprint.own_var _) (MProp.Footprint.own_var _)).1)) /-- **The loop body.** Starting from the loop invariant at rank `1`, one iteration of the loop exits with probability at least `2 * eps * (1 - eps)`. -/ diff --git a/PcolIris/Logic/Framed.lean b/PcolIris/Logic/Framed.lean index d1440ab..6e065bb 100644 --- a/PcolIris/Logic/Framed.lean +++ b/PcolIris/Logic/Framed.lean @@ -22,6 +22,18 @@ lemma Inv.footprint (π“˜ : Inv) : π“˜.to_MProp.Footprint π“˜.dom := by rw [Mem.restrict_dom] at this exact Set.inter_eq_right.mp this +/-- Every memory that `Ξ½` gives positive probability owns the variables `D`. -/ +def Distr.Owns (Ξ½ : Distr Mem) (D : Set Var) : Prop := + βˆ€ m : Mem, Ξ½ (m : WithBot Mem) β‰  0 β†’ D βŠ† m.dom + +/-- A run from `ΞΌ` to `Ξ½` does not deallocate variables. -/ +def Distr.Keeps (ΞΌ Ξ½ : Distr Mem) : Prop := + βˆ€ D, Distr.Owns ΞΌ D β†’ Distr.Owns Ξ½ D + +lemma Distr.Keeps.refl (ΞΌ : Distr Mem) : Distr.Keeps ΞΌ ΞΌ := fun _ h ↦ h + +lemma Distr.Keeps.trans {ΞΌ Ξ½ ρ : Distr Mem} (h₁ : Distr.Keeps ΞΌ Ξ½) (hβ‚‚ : Distr.Keeps Ξ½ ρ) : Distr.Keeps ΞΌ ρ := + fun D h ↦ hβ‚‚ D (h₁ D h) /-- `Framed π“˜ π“Ÿ π“Ÿfr 𝓙 ΞΌ` states that the distribution `ΞΌ` refines the product of a space `π“Ÿ` @@ -72,6 +84,21 @@ lemma right {π“Ÿβ‚ π“Ÿβ‚‚ : ProbSpace} (hd : Disjoint π“Ÿβ‚.dom π“Ÿβ‚‚.dom have hf' : Framed π“˜ (π“Ÿβ‚‚ βŠ— π“Ÿβ‚) π“Ÿfr 𝓙 ΞΌ := hf.mono hc exact hf'.left hd.symm +/-- Moving the left factor of the frame into the program's space. -/ +lemma unright {π“Ÿβ‚ π“Ÿβ‚‚ : ProbSpace} (hd₁ : Disjoint π“Ÿβ‚.dom π“Ÿfr.dom) + (hf : Framed π“˜ π“Ÿβ‚‚ (π“Ÿβ‚ βŠ— π“Ÿfr) 𝓙 ΞΌ) : Framed π“˜ (π“Ÿβ‚ βŠ— π“Ÿβ‚‚) π“Ÿfr 𝓙 ΞΌ := by + have hd : Disjoint π“Ÿβ‚‚.dom (π“Ÿβ‚.dom βˆͺ π“Ÿfr.dom) := hf.disj_frame + have h₂₁ : Disjoint π“Ÿβ‚‚.dom π“Ÿβ‚.dom := (Set.disjoint_union_right.mp hd).1 + have hβ‚‚f : Disjoint π“Ÿβ‚‚.dom π“Ÿfr.dom := (Set.disjoint_union_right.mp hd).2 + refine ⟨hf.inv, Set.disjoint_union_left.mpr ⟨hd₁, hβ‚‚f⟩, ?_, ?_⟩ + Β· have h := hf.disj_inv + change Disjoint (π“Ÿβ‚‚.dom βˆͺ (π“Ÿβ‚.dom βˆͺ π“Ÿfr.dom)) 𝓙.dom at h + change Disjoint ((π“Ÿβ‚.dom βˆͺ π“Ÿβ‚‚.dom) βˆͺ π“Ÿfr.dom) 𝓙.dom + rwa [Set.union_comm π“Ÿβ‚.dom π“Ÿβ‚‚.dom, Set.union_assoc] + Β· refine Distr.Refines.mono (ProbSpace.product_mono_left ?_ hf.disj_inv) hf.refines + exact (ProbSpace.product_mono_left (ProbSpace.product_comm h₂₁) + (Set.disjoint_union_left.mpr ⟨hβ‚‚f, hdβ‚βŸ©)).trans (ProbSpace.product_assoc π“Ÿβ‚‚ π“Ÿβ‚ π“Ÿfr) + end Framed end Pcol diff --git a/PcolIris/Logic/LemmaC6.lean b/PcolIris/Logic/LemmaC6.lean index 789e7d2..a46084a 100644 --- a/PcolIris/Logic/LemmaC6.lean +++ b/PcolIris/Logic/LemmaC6.lean @@ -23,8 +23,9 @@ open Linearization invariant `π“˜`, and let `ΞΌ` be an initial distribution framed by `π“Ÿβ‚ βŠ— π“Ÿβ‚‚`, a frame `π“Ÿfr` and a space `𝓙` satisfying the invariant. If, for an arbitrary frame `𝓕`, running thread `k` on any distribution framed by `π“Ÿβ‚–` and `𝓕` yields a distribution framed by `𝓠ₖ` and -`𝓕`, then running the two threads in parallel on `ΞΌ` yields a distribution framed by -`𝓠₁ βŠ— 𝓠₂` and `π“Ÿfr`. +`𝓕` (without deallocating variables), then running the two threads in parallel on `ΞΌ` +yields a distribution framed by `𝓠₁ βŠ— 𝓠₂` and `π“Ÿfr` (again without deallocating +variables). The side conditions of the original statement (each thread only acts on the variables it owns, and only tests its own variables) are replaced here by the requirement that the two @@ -39,11 +40,11 @@ theorem lemma_C6 {π“˜ : Inv} {p₁ pβ‚‚ : Pom (Label (WithInv Act) Test)} {π“Ÿβ‚ π“Ÿβ‚‚ 𝓠₁ 𝓠₂ π“Ÿfr 𝓙 : ProbSpace} {ΞΌ : Distr Mem} (hΞΌ : Framed π“˜ (π“Ÿβ‚ βŠ— π“Ÿβ‚‚) π“Ÿfr 𝓙 ΞΌ) (h₁ : βˆ€ (𝓕 𝓙₁ : ProbSpace) (μ₁ : Distr Mem), Framed π“˜ π“Ÿβ‚ 𝓕 𝓙₁ μ₁ β†’ - βˆ€ ν₁ ∈ ConvexPowerset.singleton' μ₁ >>= 𝓛 p₁, βˆƒ 𝓙₁', Framed π“˜ 𝓠₁ 𝓕 𝓙₁' ν₁) + βˆ€ ν₁ ∈ ConvexPowerset.singleton' μ₁ >>= 𝓛 p₁, Distr.Keeps μ₁ ν₁ ∧ βˆƒ 𝓙₁', Framed π“˜ 𝓠₁ 𝓕 𝓙₁' ν₁) (hβ‚‚ : βˆ€ (𝓕 𝓙₂ : ProbSpace) (ΞΌβ‚‚ : Distr Mem), Framed π“˜ π“Ÿβ‚‚ 𝓕 𝓙₂ ΞΌβ‚‚ β†’ - βˆ€ Ξ½β‚‚ ∈ ConvexPowerset.singleton' ΞΌβ‚‚ >>= 𝓛 pβ‚‚, βˆƒ 𝓙₂', Framed π“˜ 𝓠₂ 𝓕 𝓙₂' Ξ½β‚‚) : + βˆ€ Ξ½β‚‚ ∈ ConvexPowerset.singleton' ΞΌβ‚‚ >>= 𝓛 pβ‚‚, Distr.Keeps ΞΌβ‚‚ Ξ½β‚‚ ∧ βˆƒ 𝓙₂', Framed π“˜ 𝓠₂ 𝓕 𝓙₂' Ξ½β‚‚) : βˆ€ Ξ½ ∈ ConvexPowerset.singleton' ΞΌ >>= 𝓛 (Pom.Semantics.par p₁ pβ‚‚), - βˆƒ 𝓙', Framed π“˜ (𝓠₁ βŠ— 𝓠₂) π“Ÿfr 𝓙' Ξ½ := by + Distr.Keeps ΞΌ Ξ½ ∧ βˆƒ 𝓙', Framed π“˜ (𝓠₁ βŠ— 𝓠₂) π“Ÿfr 𝓙' Ξ½ := by sorry end Pcol diff --git a/PcolIris/Logic/WeakestPre.lean b/PcolIris/Logic/WeakestPre.lean index 7d3c503..ebdd077 100644 --- a/PcolIris/Logic/WeakestPre.lean +++ b/PcolIris/Logic/WeakestPre.lean @@ -21,10 +21,14 @@ def wp_base (π“˜ : Inv) (F : ProbSpace β†’ Prop) (c : Cmd Act) (ψ : OProp) : O Framed π“˜ π“Ÿ π“Ÿfr 𝓙 ΞΌ β†’ -- Take any `Ξ½` that results from running the program βˆ€ Ξ½ ∈ ConvexPowerset.singleton' ΞΌ >>= 𝓛 (c.withInv π“˜).to_pom, - -- Then `Ξ½` refines some probability space `𝓠`, which satisfies the postcondition `ψ`, - -- together with the same frame and a space satisfying the invariant - βˆƒ 𝓠 𝓙', Framed π“˜ 𝓠 π“Ÿfr 𝓙' Ξ½ ∧ ψ 𝓠 - upcl := fun hle h ΞΌ π“Ÿfr 𝓙 hF hf Ξ½ hΞ½ ↦ h ΞΌ π“Ÿfr 𝓙 hF (hf.mono hle) Ξ½ hΞ½ + -- Then the program has not deallocated variables, and `Ξ½` refines some probability + -- space `𝓠`, which satisfies the postcondition `ψ`, together with the same frame and a + -- space satisfying the invariant. The program does not acquire variables either: `𝓠` + -- owns no more variables than `π“Ÿ`. + Distr.Keeps ΞΌ Ξ½ ∧ βˆƒ 𝓠 𝓙', Framed π“˜ 𝓠 π“Ÿfr 𝓙' Ξ½ ∧ 𝓠.dom βŠ† π“Ÿ.dom ∧ ψ 𝓠 + upcl := fun hle h ΞΌ π“Ÿfr 𝓙 hF hf Ξ½ hΞ½ ↦ + let ⟨hk, 𝓠, 𝓙', hf', hdom, hψ⟩ := h ΞΌ π“Ÿfr 𝓙 hF (hf.mono hle) Ξ½ hΞ½ + ⟨hk, 𝓠, 𝓙', hf', hdom.trans (ProbSpace.dom_mono hle), hψ⟩ /-- The standard "strong" wp allows any frame -/ def wp (π“˜ : Inv) : Cmd Act β†’ OProp β†’ OProp := wp_base π“˜ (fun _ ↦ True) @@ -40,24 +44,25 @@ notation π“˜ " ⊒{{" Ο† "}} " c " {{" ψ "}}" => Ο† ⊒ wp π“˜ c ψ variable {π“˜ : Inv} {F : ProbSpace β†’ Prop} {c : Cmd Act} +/-- The `Skip` rule. -/ lemma wp_skip (Ο† : OProp) : - Ο† ⊣⊒ wp_base π“˜ F Cmd.skip Ο† := by - constructor - Β· intro π“Ÿ hΟ† ΞΌ π“Ÿfr 𝓙 _ hf Ξ½ hΞ½ - refine βŸ¨π“Ÿ, 𝓙, ?_, hΟ†βŸ© - rw [Cmd.withInv, Cmd.to_pom, Pom.Semantics.lin_skip, bind_pure] at hΞ½ - obtain ⟨μ, rfl⟩ := PMF.to_distr_inv hf.refines.bot_0 - have heq : Ξ½ = ΞΌ.to_distr := sorry - rwa [heq] - Β· intro π“Ÿ hΟ†; sorry + Ο† ⊒ wp_base π“˜ F Cmd.skip Ο† := by + intro π“Ÿ hΟ† ΞΌ π“Ÿfr 𝓙 _ hf Ξ½ hΞ½ + rw [Cmd.withInv, Cmd.to_pom, Pom.Semantics.lin_skip, bind_pure] at hΞ½ + have hle : ΞΌ ≀ Ξ½ := by + have : Ξ½ ∈ (ConvexPowerset.singleton' ΞΌ).set := hΞ½ + rwa [ConvexPowerset.singleton'_set_eq] at this + rw [← proper_dist_maximal hf.refines.bot_0 hle] + exact ⟨Distr.Keeps.refl ΞΌ, π“Ÿ, 𝓙, hf, subset_rfl, hΟ†βŸ© lemma wp_seq {c₁ cβ‚‚ : Cmd Act} {ψ : OProp} : wp_base π“˜ F c₁ (wp_base π“˜ F cβ‚‚ ψ) ⊒ wp_base π“˜ F (Cmd.seq c₁ cβ‚‚) ψ := by intro π“Ÿ h ΞΌ π“Ÿfr 𝓙 hF href Ξ½; rw [Cmd.withInv, Cmd.to_pom, Pom.lin_seq, ← bind_assoc] intro hΞ½; rcases ConvexPowerset.mem_bind.mp hΞ½ with ⟨ξ, hΞΎ, f, hf, rfl⟩ - have βŸ¨π“‘, 𝓙', href', h'⟩ := h ΞΌ π“Ÿfr 𝓙 hF href ΞΎ hΞΎ - refine h' ΞΎ π“Ÿfr 𝓙' hF href' _ ?_ - exact ConvexPowerset.mem_bind.mpr ⟨ξ, ConvexPowerset.self_mem_singleton' _, f, hf, rfl⟩ + have ⟨hk, 𝓑, 𝓙', href', hdom, h'⟩ := h ΞΌ π“Ÿfr 𝓙 hF href ΞΎ hΞΎ + obtain ⟨hk', 𝓠, 𝓙'', hf'', hdom', hψ⟩ := h' ΞΎ π“Ÿfr 𝓙' hF href' _ + (ConvexPowerset.mem_bind.mpr ⟨ξ, ConvexPowerset.self_mem_singleton' _, f, hf, rfl⟩) + exact ⟨Distr.Keeps.trans hk hk', 𝓠, 𝓙'', hf'', hdom'.trans hdom, hψ⟩ lemma wp_if_true {b : Expr} {c₁ cβ‚‚ : Cmd Act} {Ο† ψ : OProp} : ⌈b == Expr.literal 1βŒ‰ ∧ wp_base π“˜ F c₁ ψ ⊒ wp_base π“˜ F (Cmd.if_stmt b c₁ cβ‚‚) ψ := by @@ -122,31 +127,33 @@ lemma wp_par {π“˜ : Inv} {c₁ cβ‚‚ : Cmd Act} {Οˆβ‚ Οˆβ‚‚ : OProp} have hf' := hf.mono hle obtain βŸ¨Ξ½β‚, hΞ½β‚βŸ© := (ConvexPowerset.singleton' ΞΌ >>= 𝓛 (c₁.withInv π“˜).to_pom).nonempty obtain βŸ¨Ξ½β‚‚, hΞ½β‚‚βŸ© := (ConvexPowerset.singleton' ΞΌ >>= 𝓛 (cβ‚‚.withInv π“˜).to_pom).nonempty - obtain ⟨_, _, -, hΟˆβ‚'⟩ := h₁ ΞΌ _ 𝓙 True.intro (hf'.left hdisj) ν₁ hν₁ - obtain ⟨_, _, -, hΟˆβ‚‚'⟩ := hβ‚‚ ΞΌ _ 𝓙 True.intro (hf'.right hdisj) Ξ½β‚‚ hΞ½β‚‚ + obtain ⟨-, 𝓑₁, _, -, hdom₁, hΟˆβ‚'⟩ := h₁ ΞΌ _ 𝓙 True.intro (hf'.left hdisj) ν₁ hν₁ + obtain ⟨-, 𝓑₂, _, -, hdomβ‚‚, hΟˆβ‚‚'⟩ := hβ‚‚ ΞΌ _ 𝓙 True.intro (hf'.right hdisj) Ξ½β‚‚ hΞ½β‚‚ obtain βŸ¨π“ β‚, hQβ‚βŸ© := hΟˆβ‚ _ hΟˆβ‚' obtain βŸ¨π“ β‚‚, hQβ‚‚βŸ© := hΟˆβ‚‚ _ hΟˆβ‚‚' -- Each thread, run in isolation with an arbitrary frame, establishes its postcondition; -- by precision, the least such postcondition space is `𝓠ₖ` have hthread₁ : βˆ€ (𝓕 𝓙₁ : ProbSpace) (μ₁ : Distr Mem), Framed π“˜ π“Ÿβ‚ 𝓕 𝓙₁ μ₁ β†’ βˆ€ ν₁ ∈ ConvexPowerset.singleton' μ₁ >>= 𝓛 (c₁.withInv π“˜).to_pom, - βˆƒ 𝓙₁', Framed π“˜ 𝓠₁ 𝓕 𝓙₁' ν₁ := by + Distr.Keeps μ₁ ν₁ ∧ βˆƒ 𝓙₁', Framed π“˜ 𝓠₁ 𝓕 𝓙₁' ν₁ := by intro 𝓕 𝓙₁ μ₁ hf₁ ν₁ hν₁ - obtain βŸ¨π“ , 𝓙₁', hf', hψ⟩ := h₁ μ₁ 𝓕 𝓙₁ True.intro hf₁ ν₁ hν₁ - exact βŸ¨π“™β‚', hf'.mono ((hQ₁ 𝓠).mpr hψ)⟩ + obtain ⟨hk, 𝓠, 𝓙₁', hf', -, hψ⟩ := h₁ μ₁ 𝓕 𝓙₁ True.intro hf₁ ν₁ hν₁ + exact ⟨hk, 𝓙₁', hf'.mono ((hQ₁ 𝓠).mpr hψ)⟩ have hthreadβ‚‚ : βˆ€ (𝓕 𝓙₂ : ProbSpace) (ΞΌβ‚‚ : Distr Mem), Framed π“˜ π“Ÿβ‚‚ 𝓕 𝓙₂ ΞΌβ‚‚ β†’ βˆ€ Ξ½β‚‚ ∈ ConvexPowerset.singleton' ΞΌβ‚‚ >>= 𝓛 (cβ‚‚.withInv π“˜).to_pom, - βˆƒ 𝓙₂', Framed π“˜ 𝓠₂ 𝓕 𝓙₂' Ξ½β‚‚ := by + Distr.Keeps ΞΌβ‚‚ Ξ½β‚‚ ∧ βˆƒ 𝓙₂', Framed π“˜ 𝓠₂ 𝓕 𝓙₂' Ξ½β‚‚ := by intro 𝓕 𝓙₂ ΞΌβ‚‚ hfβ‚‚ Ξ½β‚‚ hΞ½β‚‚ - obtain βŸ¨π“ , 𝓙₂', hf', hψ⟩ := hβ‚‚ ΞΌβ‚‚ 𝓕 𝓙₂ True.intro hfβ‚‚ Ξ½β‚‚ hΞ½β‚‚ - exact βŸ¨π“™β‚‚', hf'.mono ((hQβ‚‚ 𝓠).mpr hψ)⟩ + obtain ⟨hk, 𝓠, 𝓙₂', hf', -, hψ⟩ := hβ‚‚ ΞΌβ‚‚ 𝓕 𝓙₂ True.intro hfβ‚‚ Ξ½β‚‚ hΞ½β‚‚ + exact ⟨hk, 𝓙₂', hf'.mono ((hQβ‚‚ 𝓠).mpr hψ)⟩ -- The parallel composition is handled by Lemma C.6 rw [Cmd.withInv, Cmd.to_pom] at hΞ½ - obtain βŸ¨π“™', hf''⟩ := lemma_C6 hf' hthread₁ hthreadβ‚‚ Ξ½ hΞ½ - -- We still need to prove that `𝓠₁` and `𝓠₂` own disjoint variables, which requires - -- knowing that the footprint of a postcondition is contained in that of the precondition - exact βŸ¨π“ β‚ βŠ— 𝓠₂, 𝓙', hf'', - 𝓠₁, 𝓠₂, sorry, le_refl _, (hQ₁ 𝓠₁).mp (le_refl _), (hQβ‚‚ 𝓠₂).mp (le_refl _)⟩ + obtain ⟨hk, 𝓙', hf''⟩ := lemma_C6 hf' hthread₁ hthreadβ‚‚ Ξ½ hΞ½ + -- The least models own no more variables than the preconditions of the two threads + have hsub₁ : 𝓠₁.dom βŠ† π“Ÿβ‚.dom := (ProbSpace.dom_mono ((hQ₁ _).mpr hΟˆβ‚')).trans hdom₁ + have hsubβ‚‚ : 𝓠₂.dom βŠ† π“Ÿβ‚‚.dom := (ProbSpace.dom_mono ((hQβ‚‚ _).mpr hΟˆβ‚‚')).trans hdomβ‚‚ + refine ⟨hk, 𝓠₁ βŠ— 𝓠₂, 𝓙', hf'', ?_, + 𝓠₁, 𝓠₂, hdisj.mono hsub₁ hsubβ‚‚, le_refl _, (hQ₁ 𝓠₁).mp (le_refl _), (hQβ‚‚ 𝓠₂).mp (le_refl _)⟩ + exact (Set.union_subset_union hsub₁ hsubβ‚‚).trans (ProbSpace.dom_mono hle) /- STRUCTURAL RULES -/ @@ -154,8 +161,8 @@ variable {ΞΉ : Type} [Countable ΞΉ] {π“˜ : Inv} {F : ProbSpace β†’ Prop} {c : C lemma wp_conseq (h : Ο† ⊒ ψ) : wp_base π“˜ F c Ο† ⊒ wp_base π“˜ F c ψ := by intro π“Ÿ hc ΞΌ π“Ÿfr 𝓙 hF hf Ξ½ hΞ½ - have βŸ¨π“ , 𝓙', hf', hΟ†βŸ© := hc ΞΌ π“Ÿfr 𝓙 hF hf Ξ½ hΞ½ - exact βŸ¨π“ , 𝓙', hf', h 𝓠 hΟ†βŸ© + have ⟨hk, 𝓠, 𝓙', hf', hdom, hΟ†βŸ© := hc ΞΌ π“Ÿfr 𝓙 hF hf Ξ½ hΞ½ + exact ⟨hk, 𝓠, 𝓙', hf', hdom, h 𝓠 hΟ†βŸ© lemma wp_split {ψ : ΞΉ β†’ OProp} : (⨁[ ΞΎ ] fun v ↦ wp_base π“˜ F c (ψ v)) ⊒ wp_base π“˜ F c (⨁[ ΞΎ ] ψ) := by @@ -176,10 +183,19 @@ lemma wp_strengthen (h : ψ.Precise) : wp_weak π“˜ c ψ ⊒ wp π“˜ c ψ := by sorry +/-- The `Frame` rule: a frame that is independent of the program's resources is preserved. -/ lemma wp_frame : Ο† βˆ— wp π“˜ c ψ ⊒ wp π“˜ c iprop(Ο† βˆ— ψ) := by - -- Plan: run the program with the frame `𝓕 βŠ— π“Ÿβ‚`, and rearrange the products. - sorry + rintro π“Ÿ βŸ¨π“Ÿβ‚, π“Ÿβ‚‚, hd, hle, hΟ†, hwp⟩ ΞΌ 𝓕 𝓙 _ hf Ξ½ hΞ½ + have hf' := hf.mono hle + have hd₁ : Disjoint π“Ÿβ‚.dom 𝓕.dom := + hf'.disj_frame.mono_left (Set.subset_union_left : π“Ÿβ‚.dom βŠ† π“Ÿβ‚.dom βˆͺ π“Ÿβ‚‚.dom) + -- Run the program with the frame extended by `π“Ÿβ‚` + obtain ⟨hk, 𝓠, 𝓙', hf'', hdom, hψ⟩ := hwp ΞΌ (π“Ÿβ‚ βŠ— 𝓕) 𝓙 True.intro (hf'.right hd) Ξ½ hΞ½ + have hd' : Disjoint π“Ÿβ‚.dom 𝓠.dom := + (Set.disjoint_union_right.mp hf''.disj_frame).1.symm + refine ⟨hk, π“Ÿβ‚ βŠ— 𝓠, 𝓙', hf''.unright hd₁, ?_, π“Ÿβ‚, 𝓠, hd', le_refl _, hΟ†, hψ⟩ + exact (Set.union_subset_union_right _ hdom).trans (ProbSpace.dom_mono hle) /-- **Assignment rule that preserves the value of the assigned expression.** diff --git a/PcolIris/OProp/Laws.lean b/PcolIris/OProp/Laws.lean index c680e83..f71647e 100644 --- a/PcolIris/OProp/Laws.lean +++ b/PcolIris/OProp/Laws.lean @@ -55,6 +55,69 @@ lemma state_le_product_right {p q : ProbSpace} (hdisj : Disjoint p.dom q.dom) (n end ProbSpace +namespace MProp + +/-- The pure assertion `P` only talks about the variables `V`: it requires them to be +allocated, and only depends on their values. -/ +def Footprint (P : MProp) (V : Set Var) : Prop := + βˆ€ Οƒ, P Οƒ ↔ V βŠ† Οƒ.dom ∧ P (Οƒ.restrict V) + +namespace Footprint + +lemma emp : (Iris.BI.BIBase.emp : MProp).Footprint βˆ… := + fun _ ↦ ⟨fun _ ↦ ⟨Set.empty_subset _, trivial⟩, fun _ ↦ trivial⟩ + +lemma var_equals_literal (x : Var) (v : Val) : ($ x == Expr.literal v).Footprint {x} := by + intro Οƒ + rw [Expr.var_equals_literal_iff, Expr.var_equals_literal_iff, + Mem.restrict_apply_of_mem _ (Set.mem_singleton x)] + exact ⟨fun h ↦ ⟨Set.singleton_subset_iff.mpr (Mem.mem_dom_of_eq_some h), h⟩, fun h ↦ h.2⟩ + +lemma own_var (x : Var) : (own ($ x)).Footprint {x} := by + intro Οƒ + rw [own_var_iff, own_var_iff, Mem.restrict_apply_of_mem _ (Set.mem_singleton x)] + refine ⟨fun h ↦ ⟨Set.singleton_subset_iff.mpr ?_, h⟩, fun h ↦ h.2⟩ + exact Mem.mem_dom_iff.mpr (Option.isSome_iff_ne_none.mp h) + +/-- An equation between an expression and a literal only talks about the variables that the +expression reads. -/ +lemma equals_literal {e : Expr} {V : Set Var} (hmono : Expr.Mono e) + (hread : βˆ€ Οƒ, e Οƒ = e (Οƒ.restrict V)) (hdef : βˆ€ Οƒ, (e Οƒ).isSome β†’ V βŠ† Οƒ.dom) (c : Val) : + (e == Expr.literal c).Footprint V := by + intro Οƒ + rw [Expr.equals_iff hmono (Expr.literal_mono c), Expr.equals_iff hmono (Expr.literal_mono c), + ← hread Οƒ] + exact ⟨fun h ↦ ⟨hdef Οƒ h.1, h⟩, fun h ↦ h.2⟩ + +lemma sep {P Q : MProp} {V W : Set Var} (hP : P.Footprint V) (hQ : Q.Footprint W) + (hVW : Disjoint V W) : iprop(P βˆ— Q).Footprint (V βˆͺ W) := by + intro Οƒ + constructor + Β· rintro βŸ¨Οƒβ‚, Οƒβ‚‚, hd, hle, h₁, hβ‚‚βŸ© + have hP' : P Οƒ := P.upcl ((Mem.le_union_left σ₁ Οƒβ‚‚).trans hle) h₁ + have hQ' : Q Οƒ := Q.upcl ((Mem.le_union_right hd).trans hle) hβ‚‚ + refine ⟨Set.union_subset ((hP Οƒ).mp hP').1 ((hQ Οƒ).mp hQ').1, + Οƒ.restrict V, Οƒ.restrict W, ?_, ?_, ((hP Οƒ).mp hP').2, ((hQ Οƒ).mp hQ').2⟩ + Β· exact hVW.mono (Mem.dom_restrict_subset Οƒ V) (Mem.dom_restrict_subset Οƒ W) + Β· rw [Mem.restrict_union_restrict] + Β· rintro ⟨-, h⟩ + exact iprop(P βˆ— Q).upcl (Mem.restrict_le Οƒ (V βˆͺ W)) h + +lemma and {P Q : MProp} {V W : Set Var} (hP : P.Footprint V) (hQ : Q.Footprint W) : + iprop(P ∧ Q).Footprint (V βˆͺ W) := by + intro Οƒ + change P Οƒ ∧ Q Οƒ ↔ V βˆͺ W βŠ† Οƒ.dom ∧ (P (Οƒ.restrict (V βˆͺ W)) ∧ Q (Οƒ.restrict (V βˆͺ W))) + rw [hP Οƒ, hQ Οƒ, hP (Οƒ.restrict (V βˆͺ W)), hQ (Οƒ.restrict (V βˆͺ W)), Mem.restrict_restrict, + Mem.restrict_restrict, Mem.restrict_dom, + Set.inter_eq_right.mpr (Set.subset_union_left : V βŠ† V βˆͺ W), + Set.inter_eq_right.mpr (Set.subset_union_right : W βŠ† V βˆͺ W)] + simp only [Set.union_subset_iff, Set.subset_inter_iff] + tauto + +end Footprint + +end MProp + namespace OProp /-- @@ -83,11 +146,37 @@ lemma sure_sep_intro {P Q : MProp} : iprop(⌈PβŒ‰ βˆ— ⌈QβŒ‰) ⊒ ⌈ iprop(P Β· have := hg.state n hn rwa [ProbSpace.product_state] at this -lemma sure_sep {P Q : MProp} : - ⌈ iprop(P βˆ— Q) βŒ‰ ⊣⊒ ⌈PβŒ‰ βˆ— ⌈QβŒ‰ := by - constructor - Β· intro π“Ÿ hsure; sorry - Β· exact sure_sep_intro +/-- A certainty about a separating conjunction can be split into independent certainties, when +the two assertions talk about fixed sets of variables: the two parts are the spaces without +probabilistic information over those variables. -/ +lemma sure_sep_elim {P Q : MProp} {V W : Set Var} (hP : P.Footprint V) (hQ : Q.Footprint W) : + ⌈ iprop(P βˆ— Q) βŒ‰ ⊒ iprop(⌈PβŒ‰ βˆ— ⌈QβŒ‰) := by + intro π“Ÿ h + -- The components of a memory satisfying `P βˆ— Q` satisfy `P` and `Q` + have hsplit : βˆ€ k ∈ π“Ÿ.support, P (π“Ÿ.state k) ∧ Q (π“Ÿ.state k) := by + intro k hk + obtain βŸ¨Οƒβ‚, Οƒβ‚‚, hd, hle, h₁, hβ‚‚βŸ© := h hk + exact ⟨P.upcl ((Mem.le_union_left σ₁ Οƒβ‚‚).trans hle) h₁, + Q.upcl ((Mem.le_union_right hd).trans hle) hβ‚‚βŸ© + obtain ⟨kβ‚€, hkβ‚€βŸ© := ProbSpace.support_nonempty π“Ÿ + obtain βŸ¨Οƒβ‚, Οƒβ‚‚, hd, hle, h₁, hβ‚‚βŸ© := h hkβ‚€ + have hV : V βŠ† π“Ÿ.dom := by + rw [← π“Ÿ.dom_valid kβ‚€]; exact ((hP _).mp (hsplit kβ‚€ hkβ‚€).1).1 + have hW : W βŠ† π“Ÿ.dom := by + rw [← π“Ÿ.dom_valid kβ‚€]; exact ((hQ _).mp (hsplit kβ‚€ hkβ‚€).2).1 + have hVW : Disjoint V W := hd.mono ((hP _).mp h₁).1 ((hQ _).mp hβ‚‚).1 + refine ⟨ProbSpace.forget π“Ÿ V hV, ProbSpace.forget π“Ÿ W hW, hVW, + ProbSpace.product_forget_le (ProbSpace.forget_le π“Ÿ hV) hW, fun k _ ↦ ?_, fun k _ ↦ ?_⟩ + Β· obtain ⟨k', hk', heq⟩ := ProbSpace.forget_state_restrict π“Ÿ hV k + change P ((ProbSpace.forget π“Ÿ V hV).state k) + rw [heq]; exact ((hP _).mp (hsplit k' hk').1).2 + Β· obtain ⟨k', hk', heq⟩ := ProbSpace.forget_state_restrict π“Ÿ hW k + change Q ((ProbSpace.forget π“Ÿ W hW).state k) + rw [heq]; exact ((hQ _).mp (hsplit k' hk').2).2 + +lemma sure_sep {P Q : MProp} {V W : Set Var} (hP : P.Footprint V) (hQ : Q.Footprint W) : + ⌈ iprop(P βˆ— Q) βŒ‰ ⊣⊒ ⌈PβŒ‰ βˆ— ⌈QβŒ‰ := + ⟨sure_sep_elim hP hQ, sure_sep_intro⟩ /-- A frame can be pushed into the branches of an outcome conjunction. -/ lemma oplus_distrib {ΞΉ : Type} [Countable ΞΉ] (ΞΎ : PMF ΞΉ) (Ο† : ΞΉ β†’ OProp) (ψ : OProp) : @@ -100,9 +189,67 @@ lemma oplus_distrib {ΞΉ : Type} [Countable ΞΉ] (ΞΎ : PMF ΞΉ) (Ο† : ΞΉ β†’ OProp) ((ProbSpace.product_mono_left hsum hd).trans hle) Β· exact βŸ¨π“  v, mβ‚‚, (hdom v).symm β–Έ hd.mono_left hV, le_refl _, hΟ† v hv, hψ⟩ -lemma oplus_distrib' {ΞΉ : Type} [Countable ΞΉ] (ΞΎ : PMF ΞΉ) (Ο† : ΞΉ β†’ OProp) (ψ : OProp) (h : ψ.Precise) : - (⨁[ ΞΎ ] fun v ↦ iprop(Ο† v βˆ— ψ)) ⊒ (⨁[ ΞΎ ] Ο†) βˆ— ψ := by - sorry +/-- A precise frame can be pulled out of the branches of an outcome conjunction. The frame +is satisfied by the same (least) space in every branch, and the rest of each branch, completed +by the variables it does not constrain, is independent of it. -/ +lemma oplus_distrib' {ΞΉ : Type} [Countable ΞΉ] (ΞΎ : PMF ΞΉ) (Ο† : ΞΉ β†’ OProp) (ψ : OProp) + (h : ψ.Precise) : (⨁[ ΞΎ ] fun v ↦ iprop(Ο† v βˆ— ψ)) ⊒ (⨁[ ΞΎ ] Ο†) βˆ— ψ := by + classical + rintro π“Ÿ βŸ¨π“‘, W, hdsj, hdom, hsum, hΟ†ΟˆβŸ© + obtain ⟨vβ‚€, hvβ‚€βŸ© := ΞΎ.support_nonempty + choose m₁ mβ‚‚ hd hle h₁ hβ‚‚ using hΟ†Οˆ + obtain βŸ¨π“ , hQ⟩ := h _ (hβ‚‚ vβ‚€ hvβ‚€) + have hQle : βˆ€ v (hv : v ∈ ΞΎ.support), 𝓠 ≀ mβ‚‚ v hv := fun v hv ↦ (hQ _).mpr (hβ‚‚ v hv) + have hsubW : βˆ€ v (hv : v ∈ ΞΎ.support), (m₁ v hv).dom βˆͺ (mβ‚‚ v hv).dom βŠ† W := fun v hv ↦ by + rw [← hdom v]; exact ProbSpace.dom_mono (hle v hv) + have hQW : 𝓠.dom βŠ† W := + (ProbSpace.dom_mono (hQle vβ‚€ hvβ‚€)).trans (Set.subset_union_right.trans (hsubW vβ‚€ hvβ‚€)) + set D := W \ 𝓠.dom with hD + have hm₁Q : βˆ€ v (hv : v ∈ ΞΎ.support), Disjoint (m₁ v hv).dom 𝓠.dom := + fun v hv ↦ (hd v hv).mono_right (ProbSpace.dom_mono (hQle v hv)) + have hm₁D : βˆ€ v (hv : v ∈ ΞΎ.support), (m₁ v hv).dom βŠ† D := fun v hv x hx ↦ + ⟨Set.subset_union_left.trans (hsubW v hv) hx, Set.disjoint_left.mp (hm₁Q v hv) hx⟩ + have hDR : βˆ€ v, D \ βˆ… βŠ† (𝓑 v).dom := fun v ↦ by + rw [hdom v, Set.diff_empty]; exact Set.diff_subset + -- In each branch, the part of the space that does not belong to the frame + let A : βˆ€ v, v ∈ ΞΎ.support β†’ ProbSpace := fun v hv ↦ + m₁ v hv βŠ— ProbSpace.forget (𝓑 v) (D \ (m₁ v hv).dom) + ((Set.diff_subset_diff_right (Set.empty_subset _)).trans (hDR v)) + have hAdom : βˆ€ v hv, (A v hv).dom = D := fun v hv ↦ Set.union_diff_cancel (hm₁D v hv) + have hAΟ† : βˆ€ v hv, Ο† v (A v hv) := fun v hv ↦ + (Ο† v).mono (ProbSpace.le_product_left _ _) (h₁ v hv) + have hAQ : βˆ€ v hv, (A v hv βŠ— 𝓠) ≀ 𝓑 v := by + intro v hv + have hF : Disjoint 𝓠.dom (D \ (m₁ v hv).dom) := + Set.disjoint_left.mpr fun x hx hx' ↦ hx'.1.2 hx + refine (ProbSpace.product_swap_right hF ?_).trans ?_ + Β· exact Set.disjoint_union_right.mpr ⟨hm₁Q v hv, + Set.disjoint_left.mpr fun x hx hx' ↦ hx'.2 hx⟩ + Β· exact ProbSpace.product_forget_le + ((ProbSpace.product_mono_right (hQle v hv) (hm₁Q v hv)).trans (hle v hv)) _ + let A' : ΞΉ β†’ ProbSpace := fun v ↦ if hv : v ∈ ΞΎ.support then A v hv else A vβ‚€ hvβ‚€ + have hA'dom : βˆ€ v, (A' v).dom = D := fun v ↦ by + simp only [A']; split_ifs with hv + Β· exact hAdom v hv + Β· exact hAdom vβ‚€ hvβ‚€ + obtain ⟨code, hcode⟩ := Countable.exists_injective_nat ΞΉ + let S : ΞΉ β†’ ProbSpace := fun v ↦ (A' v).shift (code v) + have hSdisj : βˆ€ {i j : ΞΉ}, i β‰  j β†’ Disjoint (S i).support (S j).support := + fun hij ↦ ProbSpace.disjoint_support_shift _ _ (hcode.ne hij) + have hSdom : βˆ€ v, (S v).dom = D := hA'dom + refine ⟨ProbSpace.sum ΞΎ S D hSdisj hSdom, 𝓠, Set.disjoint_sdiff_left, ?_, + ⟨S, D, hSdisj, hSdom, le_refl _, fun v hv ↦ ?_⟩, (hQ 𝓠).mp (le_refl _)⟩ + Β· refine (ProbSpace.sum_product_le_sumProd ΞΎ S 𝓠 D hSdisj hSdom).trans + ((ProbSpace.sum_mono (ProbSpace.sum_prod_disjoint 𝓠 hSdisj) hdsj + (ProbSpace.sum_prod_dom 𝓠 hSdom) hdom (Set.union_subset Set.diff_subset hQW) + fun v hv ↦ ?_).trans hsum) + have hv' : v ∈ ΞΎ.support := (PMF.mem_support_iff _ _).mpr hv + have hA' : A' v = A v hv' := dif_pos hv' + refine (ProbSpace.product_mono_left (ProbSpace.shift_le _ _) ?_).trans ?_ + Β· rw [hA'dom]; exact Set.disjoint_sdiff_left + Β· rw [hA']; exact hAQ v hv' + Β· have hA' : A' v = A v hv := dif_pos hv + exact (Ο† v).mono (ProbSpace.le_shift _ _) (hA' β–Έ hAΟ† v hv) lemma oplus_weaken {ΞΎ : PMF Val} {Ο† ψ : Val β†’ OProp} (h : βˆ€ v ∈ ΞΎ.support, Ο† v ⊒ ψ v) : (⨁[ΞΎ] Ο†) ⊒ ⨁[ΞΎ] ψ := by @@ -173,54 +320,6 @@ lemma oplus_reindex {ΞΉ : Type} [Countable ΞΉ] {ΞΎ : PMF ΞΉ} (e : ΞΉ ≃ ΞΉ) (h end OProp -namespace MProp - -/-- The pure assertion `P` only talks about the variables `V`: it requires them to be -allocated, and only depends on their values. -/ -def Footprint (P : MProp) (V : Set Var) : Prop := - βˆ€ Οƒ, P Οƒ ↔ V βŠ† Οƒ.dom ∧ P (Οƒ.restrict V) - -namespace Footprint - -lemma emp : (Iris.BI.BIBase.emp : MProp).Footprint βˆ… := - fun _ ↦ ⟨fun _ ↦ ⟨Set.empty_subset _, trivial⟩, fun _ ↦ trivial⟩ - -lemma var_equals_literal (x : Var) (v : Val) : ($ x == Expr.literal v).Footprint {x} := by - intro Οƒ - rw [Expr.var_equals_literal_iff, Expr.var_equals_literal_iff, - Mem.restrict_apply_of_mem _ (Set.mem_singleton x)] - exact ⟨fun h ↦ ⟨Set.singleton_subset_iff.mpr (Mem.mem_dom_of_eq_some h), h⟩, fun h ↦ h.2⟩ - -lemma own_var (x : Var) : (own ($ x)).Footprint {x} := by - intro Οƒ - rw [own_var_iff, own_var_iff, Mem.restrict_apply_of_mem _ (Set.mem_singleton x)] - refine ⟨fun h ↦ ⟨Set.singleton_subset_iff.mpr ?_, h⟩, fun h ↦ h.2⟩ - exact Mem.mem_dom_iff.mpr (Option.isSome_iff_ne_none.mp h) - -/-- An equation between an expression and a literal only talks about the variables that the -expression reads. -/ -lemma equals_literal {e : Expr} {V : Set Var} (hmono : Expr.Mono e) - (hread : βˆ€ Οƒ, e Οƒ = e (Οƒ.restrict V)) (hdef : βˆ€ Οƒ, (e Οƒ).isSome β†’ V βŠ† Οƒ.dom) (c : Val) : - (e == Expr.literal c).Footprint V := by - intro Οƒ - rw [Expr.equals_iff hmono (Expr.literal_mono c), Expr.equals_iff hmono (Expr.literal_mono c), - ← hread Οƒ] - exact ⟨fun h ↦ ⟨hdef Οƒ h.1, h⟩, fun h ↦ h.2⟩ - -lemma and {P Q : MProp} {V W : Set Var} (hP : P.Footprint V) (hQ : Q.Footprint W) : - iprop(P ∧ Q).Footprint (V βˆͺ W) := by - intro Οƒ - change P Οƒ ∧ Q Οƒ ↔ V βˆͺ W βŠ† Οƒ.dom ∧ (P (Οƒ.restrict (V βˆͺ W)) ∧ Q (Οƒ.restrict (V βˆͺ W))) - rw [hP Οƒ, hQ Οƒ, hP (Οƒ.restrict (V βˆͺ W)), hQ (Οƒ.restrict (V βˆͺ W)), Mem.restrict_restrict, - Mem.restrict_restrict, Mem.restrict_dom, - Set.inter_eq_right.mpr (Set.subset_union_left : V βŠ† V βˆͺ W), - Set.inter_eq_right.mpr (Set.subset_union_right : W βŠ† V βˆͺ W)] - simp only [Set.union_subset_iff, Set.subset_inter_iff] - tauto - -end Footprint - -end MProp namespace Precise diff --git a/PcolIris/OProp/ProductLaws.lean b/PcolIris/OProp/ProductLaws.lean index e59dc05..e262e6d 100644 --- a/PcolIris/OProp/ProductLaws.lean +++ b/PcolIris/OProp/ProductLaws.lean @@ -397,6 +397,13 @@ theorem product_assoc' (p q r : ProbSpace) : (p βŠ— (q βŠ— r)) ≀ ((p βŠ— q) Equiv.prodAssoc_apply, id_eq, Mem.union_assoc] exact le_refl _ +/-- Swapping the two right factors of a nested product. -/ +lemma product_swap_right {a b c : ProbSpace} (hbc : Disjoint b.dom c.dom) + (ha : Disjoint a.dom (b.dom βˆͺ c.dom)) : ((a βŠ— c) βŠ— b) ≀ ((a βŠ— b) βŠ— c) := + (product_assoc a c b).trans + ((product_mono_right (product_comm hbc) (by rwa [Set.union_comm] at ha)).trans + (product_assoc' a b c)) + /-! ### Projections and the unit -/ /-- A product carries at least the information of its left factor. -/ diff --git a/PcolIris/OProp/SumLaws.lean b/PcolIris/OProp/SumLaws.lean index 49da442..25467c1 100644 --- a/PcolIris/OProp/SumLaws.lean +++ b/PcolIris/OProp/SumLaws.lean @@ -170,6 +170,29 @@ theorem sum_mono {π“Ÿ 𝓠 : ΞΉ β†’ ProbSpace} {V W : Set Var} rw [sumState_of_mem hQ hn, hG v hv n hn, sumState_of_mem hP ((hg v hv).mem_support hn)] exact (hg v hv).state n hn +/-- A sum over a point mass is (below) its summand. -/ +theorem sum_pure_le {π“Ÿ : ΞΉ β†’ ProbSpace} {V : Set Var} + (hP : βˆ€ {i j : ΞΉ}, i β‰  j β†’ Disjoint (π“Ÿ i).support (π“Ÿ j).support) + (hdP : βˆ€ i, (π“Ÿ i).dom = V) (i : ΞΉ) : sum (PMF.pure i) π“Ÿ V hP hdP ≀ π“Ÿ i := by + classical + have hmeas : βˆ€ E, (sumMSpace (PMF.pure i) π“Ÿ).MeasurableSet' E β†’ + (π“Ÿ i).mspace.MeasurableSet' E := by + intro E hE + have h1 := hE i (by simp) + have hnull : (π“Ÿ i).meas (E \ (π“Ÿ i).support) = 0 := + measure_mono_null (Set.diff_subset_compl _ _) (meas_compl_support _) + have h2 := (π“Ÿ i).complete.out _ hnull + have := @MeasurableSet.union β„• (π“Ÿ i).mspace _ _ h1 h2 + rwa [Set.inter_union_sdiff] at this + refine le_of_id hmeas (fun E hE ↦ ?_) (hdP i).symm.subset + (fun n hn ↦ le_of_eq (sumState_of_mem hP hn)) + refine ENNReal.coe_injective ?_ + rw [prob_coe, prob_coe] + change sumMeasure (PMF.pure i) π“Ÿ E = _ + rw [sumMeasure_apply _ _ hE, sumMeasureFun, tsum_eq_single i] + Β· rw [PMF.pure_apply_self, one_mul, meas_inter_support] + Β· intro j hj; rw [PMF.pure_apply_of_ne _ _ hj, zero_mul] + end SumMono end ProbSpace diff --git a/PcolIris/OProp/TrivialSpace.lean b/PcolIris/OProp/TrivialSpace.lean index 7448461..277dbe8 100644 --- a/PcolIris/OProp/TrivialSpace.lean +++ b/PcolIris/OProp/TrivialSpace.lean @@ -64,6 +64,88 @@ lemma trivialOn_le {𝓠 : ProbSpace} (hdom : V βŠ† 𝓠.dom) (g : β„• β†’ β„•) Β· rw [Set.preimage_empty, measure_empty, measure_empty] Β· rw [Set.preimage_univ, measure_univ, measure_univ] +/-! ### Independence of spaces without probabilistic information -/ + +/-- A space without probabilistic information is independent of every other space: if `X` is +below `Z`, and the memories of `T` are (almost surely) restrictions of those of `Z` to other +variables, then `X βŠ— T` is below `Z`. -/ +theorem product_trivialOn_le {X Z : ProbSpace} (hX : X ≀ Z) (hU : V βŠ† Z.dom) (t : β„• β†’ β„•) + (ht : βˆ€ k ∈ Z.support, f (t k) ≀ Z.state k) : (X βŠ— trivialOn V f hf) ≀ Z := by + obtain ⟨g, hg⟩ := hX + haveI := isProbabilityMeasure_meas X + haveI := isProbabilityMeasure_meas (trivialOn V f hf) + have hgm : @Measurable β„• β„• Z.mspace X.mspace g := fun E hE ↦ hg.mspace E hE + have htm : @Measurable β„• β„• Z.mspace (trivialOn V f hf).mspace t := by + intro s hs + rcases trivialOn_measurableSet hs with rfl | rfl + Β· exact Z.mspace.measurableSet_empty + Β· exact @MeasurableSet.univ β„• Z.mspace + have hmeas : @Measurable β„• (β„• Γ— β„•) Z.mspace (X.mspace.prod (trivialOn V f hf).mspace) + (fun k ↦ (g k, t k)) := + @Measurable.prodMk β„• Z.mspace β„• β„• X.mspace (trivialOn V f hf).mspace g t hgm htm + have hmap : MP Z.mspace (X.mspace.prod (trivialOn V f hf).mspace) (fun k ↦ (g k, t k)) + Z.meas (@Measure.prod β„• β„• X.mspace (trivialOn V f hf).mspace X.meas + (trivialOn V f hf).meas) := by + refine @MeasurePreserving.mk β„• (β„• Γ— β„•) Z.mspace (X.mspace.prod (trivialOn V f hf).mspace) + _ _ _ hmeas ?_ + symm + refine @ext_of_generate_finite _ (X.mspace.prod (trivialOn V f hf).mspace) _ _ + (Set.image2 (fun x1 x2 ↦ x1 Γ—Λ’ x2) {s | @MeasurableSet β„• X.mspace s} + {t | @MeasurableSet β„• (trivialOn V f hf).mspace t}) + (@generateFrom_prod β„• β„• X.mspace (trivialOn V f hf).mspace).symm + (@isPiSystem_prod β„• β„• X.mspace (trivialOn V f hf).mspace) inferInstance ?_ ?_ + Β· rintro _ ⟨A, hA, B, hB, rfl⟩ + rw [@Measure.map_apply β„• (β„• Γ— β„•) Z.mspace (X.mspace.prod (trivialOn V f hf).mspace) + Z.meas _ hmeas _ (@MeasurableSet.prod β„• β„• X.mspace (trivialOn V f hf).mspace A B hA hB), + @Measure.prod_prod β„• β„• X.mspace (trivialOn V f hf).mspace X.meas _ _ A B] + rcases trivialOn_measurableSet (V := V) (f := f) (hf := hf) hB with rfl | rfl + Β· simp + Β· rw [measure_univ, mul_one, Set.mk_preimage_prod, Set.preimage_univ, Set.inter_univ] + exact (hg.measurePreserving.measure_preimage + (@MeasurableSet.nullMeasurableSet β„• X.mspace X.meas A hA)).symm + Β· rw [@Measure.map_apply β„• (β„• Γ— β„•) Z.mspace (X.mspace.prod (trivialOn V f hf).mspace) + Z.meas _ hmeas _ MeasurableSet.univ, Set.preimage_univ, measure_univ, measure_univ] + refine ⟨fun k ↦ Nat.pairEquiv (g k, t k), + relabels_of_measurePreserving (IsCompletionOf.product X (trivialOn V f hf)) + ((measurePreserving_pair X _).comp hmap) (Set.union_subset hg.dom hU) ?_⟩ + intro k hk + rw [product_state, Equiv.symm_apply_apply] + exact Mem.union_le (hg.state k hk) (ht k hk) + +/-- The part of `Z` over the variables `U`, forgetting all probabilistic information: its +memories are the (possible) memories of `Z`, restricted to `U`. -/ +noncomputable def forget (Z : ProbSpace) (U : Set Var) (hU : U βŠ† Z.dom) : ProbSpace := + open Classical in + trivialOn U + (fun k ↦ (Z.state (if k ∈ Z.support then k else (support_nonempty Z).some)).restrict U) + (fun k ↦ by rw [Mem.restrict_dom, Z.dom_valid]; exact Set.inter_eq_right.mpr hU) + +lemma forget_state_restrict (Z : ProbSpace) {U : Set Var} (hU : U βŠ† Z.dom) (k : β„•) : + βˆƒ k' ∈ Z.support, (forget Z U hU).state k = (Z.state k').restrict U := by + classical + by_cases hk : k ∈ Z.support + Β· exact ⟨k, hk, by simp only [forget, trivialOn, if_pos hk]⟩ + Β· exact ⟨_, (support_nonempty Z).some_mem, by simp only [forget, trivialOn, if_neg hk]⟩ + +lemma forget_state_of_mem (Z : ProbSpace) {U : Set Var} (hU : U βŠ† Z.dom) {k : β„•} + (hk : k ∈ Z.support) : (forget Z U hU).state k = (Z.state k).restrict U := by + classical + simp only [forget, trivialOn, if_pos hk] + +lemma support_forget (Z : ProbSpace) {U : Set Var} (hU : U βŠ† Z.dom) : + (forget Z U hU).support = Set.univ := support_trivialOn + +lemma forget_le (Z : ProbSpace) {U : Set Var} (hU : U βŠ† Z.dom) : forget Z U hU ≀ Z := + trivialOn_le hU id fun k hk ↦ by + change (forget Z U hU).state k ≀ _ + rw [forget_state_of_mem Z hU hk]; exact Mem.restrict_le _ _ + +lemma product_forget_le {X Z : ProbSpace} (hX : X ≀ Z) {U : Set Var} (hU : U βŠ† Z.dom) : + (X βŠ— forget Z U hU) ≀ Z := + product_trivialOn_le hX hU id fun k hk ↦ by + change (forget Z U hU).state k ≀ _ + rw [forget_state_of_mem Z hU hk]; exact Mem.restrict_le _ _ + end ProbSpace end Pcol diff --git a/PcolIris/Semantics/Mem.lean b/PcolIris/Semantics/Mem.lean index 878ee56..66a53b7 100644 --- a/PcolIris/Semantics/Mem.lean +++ b/PcolIris/Semantics/Mem.lean @@ -321,6 +321,13 @@ lemma restrict_le (Οƒ : Mem) (X : Set Var) : Οƒ.restrict X ≀ Οƒ := by Β· rwa [restrict_apply_of_mem _ h] at hx Β· rw [restrict_apply_of_notMem _ h] at hx; exact absurd hx (by simp) +lemma union_le {σ₁ Οƒβ‚‚ Οƒ : Mem} (h₁ : σ₁ ≀ Οƒ) (hβ‚‚ : Οƒβ‚‚ ≀ Οƒ) : (σ₁ ⊎ Οƒβ‚‚) ≀ Οƒ := by + rw [le_iff] at h₁ hβ‚‚ ⊒ + intro x v hx + by_cases hs : x ∈ σ₁.dom + Β· rw [union_apply_of_mem_dom hs] at hx; exact h₁ x v hx + Β· rw [union_apply_of_notMem_dom hs] at hx; exact hβ‚‚ x v hx + end Mem end Pcol