Global Instance Finite_prod {X Y} `{Finite X, Finite Y} : Finite (X * Y).
Definition indicate (b : bool) : Q :=
if b then 1 else 0.
Definition indicate_nat (b : bool) : nat :=
if b then 1 else O.

(* Specifications: *)
Lemma eval_ret {X} (x : X) (E : X -> bool) :
eval_dist (mreturn x) E ==
indicate (E x).
Lemma eval_dist_sigma_dist {X} (d : dist X) (E : X -> bool) :
eval_dist d E ==
sigma_dist d (fun x q => q * indicate (E x)).
Lemma filter_dist_app {X} (xs xs' : list (X * Q)) (p : X -> bool) :
filter_dist (xs ++ xs') p =
filter_dist xs p ++ filter_dist xs' p.
Lemma filter_dist_flat_map {X Y} (f : X -> list (Y * Q)) (xs : list X) (p : Y -> bool) :
filter_dist (flat_map f xs) p =
flat_map (fun x => filter_dist (f x) p) xs.
Lemma sum_dist_app {X} (l l' : list (X * Q)) :
sum_dist (l ++ l') == sum_dist l + sum_dist l'.
Lemma sum_dist_flat_map {X Y} (f : X -> list (Y * Q)) (xs : list X) :
sum_dist (flat_map f xs) ==
Qsum (map (fun x => sum_dist (f x)) xs).
Lemma filter_dist_update_probs {X} (l : list (X * Q)) (q : Q) (p : X -> bool) :
filter_dist (update_probs q l) p =
update_probs q (filter_dist l p).
Lemma sum_dist_update_probs {X} (l : list (X * Q)) (q : Q) :
sum_dist (update_probs q l) == q * sum_dist l.
Lemma eval_bind {X Y} (m : dist X) (f : X -> dist Y) (E : Y -> bool) :
eval_dist (mbind m f) E ==
sigma_dist m (fun x q => q * eval_dist (f x) E).
Lemma card_rev_uniform {X} `{Finite X} (d : dist X) :
(forall x, eval_dist d (Classes.eqb x) == 1 / Q_of_nat (card X)) ->
uniform d.
Lemma Qsum_scalar {X} (xs : list X) (f : X -> Q) (q : Q) :
Qsum (map (fun x => q * f x) xs) == q * Qsum (map f xs).