Skip to content

Commit 71c3b87

Browse files
[theories/modules] law of total probability
Add module-based law of total probability for lossless distributions with finite support.
1 parent 042456e commit 71c3b87

1 file changed

Lines changed: 259 additions & 0 deletions

File tree

theories/modules/TotalProb.ec

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
(*^ This theory proves a module-based law of total probability for
2+
distributions with finite support, and then specializes it to
3+
`DBool.dbool`, `drange` and `duniform`. ^*)
4+
5+
require import AllCore List StdOrder StdBigop Distr DBool.
6+
require EventPartitioning.
7+
import RealOrder Bigreal BRA.
8+
9+
(*& Are the elements in the support of a distribution the
10+
same as the elements of a list? &*)
11+
12+
op support_is (d : 'a distr) (xs : 'a list) : bool =
13+
forall (y : 'a), y \in d <=> y \in xs.
14+
15+
(*& General abstract theory &*)
16+
17+
abstract theory TotalGeneral.
18+
19+
(*& theory parameter: additional input &*)
20+
21+
type input.
22+
23+
(*& theory parameter: type of distribution &*)
24+
25+
type t.
26+
27+
(*& A module with a `main` procedure taking in an input plus
28+
a value of type `t`, and returning a boolean result. &*)
29+
30+
module type T = {
31+
proc main(i : input, x : t) : bool
32+
}.
33+
34+
(*& For a module `M` with module type `T` and a distribution `dt` for
35+
`t` plus an input `i`, `Rand(M).f(dt, i)` samples a value `x` from
36+
`dt`, passes it to `M.main` along with `i`, and returns the
37+
boolean `M.main` returns. &*)
38+
39+
module Rand(M : T) = {
40+
proc f(dt : t distr, i : input) : bool = {
41+
var b : bool; var x : t;
42+
x <$ dt;
43+
b <@ M.main(i, x);
44+
return b;
45+
}
46+
}.
47+
48+
(* skip to end of section for main lemma *)
49+
50+
section.
51+
52+
declare module M <: T.
53+
54+
local module RandAux = {
55+
var x : t (* a global variable *)
56+
57+
proc f(dt : t distr, i : input) : bool = {
58+
var b : bool;
59+
x <$ dt;
60+
b <@ M.main(i, x);
61+
return b;
62+
}
63+
}.
64+
65+
local clone EventPartitioning as EP with
66+
type input <- t distr * input,
67+
type output <- bool
68+
proof *.
69+
70+
local clone EP.ListPartitioning as EPL with
71+
type partition <- t
72+
proof *.
73+
74+
local op x_of_glob_RA (g : (glob RandAux)) : t = g.`2.
75+
local op phi (_ : t distr * input) (g : glob RandAux) (_ : bool) : t =
76+
x_of_glob_RA g.
77+
local op E (_ : t distr * input) (_ : glob RandAux) (o : bool) : bool = o.
78+
79+
local lemma RandAux_partition_eq (dt' : t distr) (i' : input) (x' : t) &m :
80+
Pr[RandAux.f(dt', i') @ &m : res /\ x_of_glob_RA (glob RandAux) = x'] =
81+
mu1 dt' x' * Pr[M.main(i', x') @ &m : res].
82+
proof.
83+
byphoare
84+
(_ :
85+
dt = dt' /\ i = i' /\ (glob M) = (glob M){m} ==>
86+
res /\ x_of_glob_RA (glob RandAux) = x') => //.
87+
proc; rewrite /x_of_glob_RA /=.
88+
seq 1 :
89+
(RandAux.x = x')
90+
(mu1 dt' x')
91+
Pr[M.main(i', x') @ &m : res]
92+
(1%r - mu1 dt x')
93+
0%r
94+
(i = i' /\ (glob M) = (glob M){m}) => //.
95+
auto.
96+
rnd (pred1 x'); auto.
97+
call (_ : i = i' /\ x = x' /\ glob M = (glob M){m} ==> res).
98+
bypr => &hr [#] -> -> glob_eq.
99+
byequiv (_ : ={i, x, glob M} ==> ={res}) => //; sim.
100+
auto.
101+
hoare; call (_ : true); auto; smt().
102+
qed.
103+
104+
lemma total_prob' (dt' : t distr) (supp : t list) (i' : input) &m :
105+
is_lossless dt' => uniq supp => support_is dt' supp =>
106+
Pr[Rand(M).f(dt', i') @ &m : res] =
107+
big predT
108+
(fun x' => mu1 dt' x' * Pr[M.main(i', x') @ &m : res])
109+
supp.
110+
proof.
111+
move => dt'_ll uniq_supp support_is_dt'_supp.
112+
have -> :
113+
Pr[Rand(M).f(dt', i') @ &m : res] = Pr[RandAux.f(dt', i') @ &m : res].
114+
byequiv (_ : ={dt, i, glob M} ==> ={res}) => //; proc; sim.
115+
rewrite (EPL.list_partitioning RandAux (dt', i') E phi supp &m) //.
116+
have -> /= :
117+
Pr[RandAux.f(dt', i') @ &m: res /\ ! (x_of_glob_RA (glob RandAux) \in supp)] =
118+
0%r.
119+
byphoare (_ : dt = dt' /\ i = i' ==> _) => //; proc.
120+
seq 1 :
121+
(RandAux.x \in supp)
122+
1%r
123+
0%r
124+
0%r
125+
1%r => //.
126+
auto.
127+
hoare; call (_ : true); auto; smt().
128+
rnd pred0; auto; smt(mu0).
129+
congr; apply fun_ext => x'; by rewrite RandAux_partition_eq.
130+
qed.
131+
132+
end section.
133+
134+
(*& total probability lemma for distributions with finite support &*)
135+
136+
lemma total_prob (M <: T) (dt : t distr) (supp : t list) (i : input) &m :
137+
is_lossless dt => uniq supp => support_is dt supp =>
138+
Pr[Rand(M).f(dt, i) @ &m : res] =
139+
big predT
140+
(fun (x : t) => mu1 dt x * Pr[M.main(i, x) @ &m : res])
141+
supp.
142+
proof.
143+
move => dt_ll uniq_supp support_is_dt_supp.
144+
by apply (total_prob' M).
145+
qed.
146+
147+
end TotalGeneral.
148+
149+
(*& Specialization to `DBool.dbool` &*)
150+
151+
abstract theory TotalBool.
152+
153+
clone include TotalGeneral with
154+
type t <- bool
155+
proof *.
156+
157+
(*& total probability lemma for `DBool.dbool` &*)
158+
159+
lemma total_prob_bool (M <: T) (i : input) &m :
160+
Pr[Rand(M).f(DBool.dbool, i) @ &m : res] =
161+
Pr[M.main(i, true) @ &m : res] / 2%r +
162+
Pr[M.main(i, false) @ &m : res] / 2%r.
163+
proof.
164+
rewrite (total_prob M DBool.dbool [true; false]) //.
165+
rewrite dbool_ll.
166+
smt(supp_dbool).
167+
by rewrite 2!big_cons big_nil /= /predT /predF /= 2!dbool1E.
168+
qed.
169+
170+
end TotalBool.
171+
172+
(*& Specialization to `drange` &*)
173+
174+
abstract theory TotalRange.
175+
176+
clone include TotalGeneral with
177+
type t <- int
178+
proof *.
179+
180+
lemma big_weight_simp (M <: T) (m n : int, i : input, ys : int list) &m :
181+
(forall y, y \in ys => m <= y < n) =>
182+
big predT
183+
(fun (x : int) => mu1 (drange m n) x * Pr[M.main(i, x) @ &m : res])
184+
ys =
185+
big predT
186+
(fun (x : int) => Pr[M.main(i, x) @ &m : res] / (n - m)%r)
187+
ys.
188+
proof.
189+
elim ys => [// | y ys IH mem_impl].
190+
rewrite 2!big_cons (_ : predT y) //=.
191+
rewrite drange1E (_ : m <= y < n) 1:mem_impl //=.
192+
rewrite IH => [z z_in_ys | //].
193+
by rewrite mem_impl /= z_in_ys.
194+
qed.
195+
196+
(*& total probability lemma for `drange` &*)
197+
198+
lemma total_prob_drange (M <: T) (m n : int, i : input) &m :
199+
m < n =>
200+
Pr[Rand(M).f(drange m n, i) @ &m : res] =
201+
bigi predT
202+
(fun (j : int) => Pr[M.main(i, j) @ &m : res] / (n - m)%r)
203+
m n.
204+
proof.
205+
move => lt_m_n.
206+
rewrite (total_prob M (drange m n) (range m n)).
207+
by rewrite drange_ll.
208+
by rewrite range_uniq.
209+
rewrite /support_is => j; smt(supp_drange mem_range).
210+
rewrite (big_weight_simp M) //; by move => j /mem_range.
211+
qed.
212+
213+
end TotalRange.
214+
215+
(*& Specialization to `duniform` &*)
216+
217+
abstract theory TotalUniform.
218+
219+
(*& theory parameter: type &*)
220+
221+
type t.
222+
223+
clone include TotalGeneral with
224+
type t <- t
225+
proof *.
226+
227+
lemma big_weight_simp (M <: T) (xs : t list, i : input, ys : t list) &m :
228+
uniq xs =>
229+
(forall y, y \in ys => y \in xs) =>
230+
big predT
231+
(fun (x : t) => mu1 (duniform xs) x * Pr[M.main(i, x) @ &m : res])
232+
ys =
233+
big predT
234+
(fun (x : t) => Pr[M.main(i, x) @ &m : res] / (size xs)%r)
235+
ys.
236+
proof.
237+
move => uniq_xs.
238+
elim ys => [// | y ys IH mem_impl].
239+
smt(big_cons duniform1E_uniq).
240+
qed.
241+
242+
(*& total probability lemma for `duniform` &*)
243+
244+
lemma total_prob_uniform (M <: T) (xs : t list, i : input) &m :
245+
uniq xs => xs <> [] =>
246+
Pr[Rand(M).f(duniform xs, i) @ &m : res] =
247+
big predT
248+
(fun (x : t) => Pr[M.main(i, x) @ &m : res] / (size xs)%r)
249+
xs.
250+
proof.
251+
move => uniq_xs xs_ne_nil.
252+
rewrite (total_prob M (duniform xs) xs).
253+
by rewrite duniform_ll.
254+
by rewrite uniq_xs.
255+
rewrite /support_is => y; smt(supp_duniform).
256+
by rewrite (big_weight_simp M).
257+
qed.
258+
259+
end TotalUniform.

0 commit comments

Comments
 (0)