Definition normalize {X} `{Finite X} (d : dist X) : dist X.

(* Specifications: *)
Lemma sigma_dist_equiv {X} `{Finite X} (d : dist X) f : sigma_dist d (fun x q => q * f x) == sigma_dist (normalize d) (fun x q => q * f x).
Lemma uniform_sigma_dist {X} `{Finite X} (d : dist X) f : uniform d -> sigma_dist d (fun x q => q * f x) == Qsum (map f enum) / Q_of_nat (card X).
Lemma eval_correct o : hoare uniform uniform (eval o).
Lemma card_prod {X Y} `{Finite X, Finite Y} : card (X * Y) = (card X * card Y)%nat.
Lemma Q_of_nat_prod (x y : nat) : Q_of_nat (x * y)%nat = Q_of_nat x * Q_of_nat y.
Lemma sumF_ext {X} `{Finite X} (f g : X -> nat) : (forall x, f x = g x) -> sumF f = sumF g.
Lemma double_sum {X Y} (xs : list X) (ys : list Y) (f : X * Y -> nat) : list_sum (map (fun x => list_sum (map (fun y => f (x, y)) ys)) xs) = list_sum (map f (list_prod xs ys)).
Lemma double_sumQ {X Y} (xs : list X) (ys : list Y) (f : X * Y -> Q) : Qsum (map (fun x => Qsum (map (fun y => f (x, y)) ys)) xs) == Qsum (map f (list_prod xs ys)).
Lemma list_sum_map_plus {X} (f g : X -> nat) (xs : list X) : list_sum (map (fun x => f x + g x)%nat xs) = (list_sum (map f xs) + list_sum (map g xs))%nat.
Lemma list_sum_map_flip {X Y} (xs : list X) (ys : list Y) (f : X -> Y -> nat) : list_sum (map (fun x => list_sum (map (f x) ys)) xs) = list_sum (map (fun y => list_sum (map (fun x => f x y) xs)) ys).
Lemma sum_remove : forall (a : nat) (l : list nat), In a l -> (a + list_sum (remove_aux Nat.eqb l a) = list_sum l)%nat.
Lemma list_sum_remove_aux_map {X} `{EqDec X} (a : X) : forall (l : list X) (f : X -> nat), In a l -> (list_sum (map f (remove_aux Classes.eqb l a)) = list_sum (remove_aux Nat.eqb (map f l) (f a)))%nat.
Lemma sum_remove_map {X} `{EqDec X} (a : X) : forall (l : list X) (f : X -> nat), In a l -> (f a + list_sum (map f (remove_aux Classes.eqb l a)))%nat = list_sum (map f l).
Lemma sum_remove_mapQ {X} `{EqDec X} (a : X) : forall (l : list X) (f : X -> Q), In a l -> (f a + Qsum (map f (remove_aux Classes.eqb l a))) == Qsum (map f l).
Lemma list_sum_map_ext {X} `{EqDec X} (f : X -> nat) (l : list X) : forall (l' : list X), NoDup l -> NoDup l' -> (forall x, In x l -> In x l') -> (forall x, In x l' -> In x l) -> list_sum (map f l) = list_sum (map f l').
Lemma list_sum_map_extQ {X} `{EqDec X} (f : X -> Q) (l : list X) : forall (l' : list X), NoDup l -> NoDup l' -> (forall x, In x l -> In x l') -> (forall x, In x l' -> In x l) -> Qsum (map f l) == Qsum (map f l').
Lemma NoDup_list_prod {X Y} (xs : list X) : forall (ys : list Y), NoDup xs -> NoDup ys -> NoDup (list_prod xs ys).
Lemma sum_2D {X Y} `{Finite X, Finite Y} (f : X * Y -> nat) : sumF f = sumF (fun x => sumF (fun y => f (x,y))).
Lemma sumFQ_2D {X Y} `{Finite X, Finite Y} (f : X * Y -> Q) : sumFQ f == sumFQ (fun x => sumFQ (fun y => f (x,y))).
Lemma sum_2D_flip {X Y} `{Finite X, Finite Y} (f : X -> Y -> nat) : sumF (fun x => sumF (f x)) = sumF (fun y => sumF (fun x => f x y)).
Lemma list_sum_indicate_empty {X} `{Finite X} (x0 : X) (xs : list X) : ~ In x0 xs -> list_sum (map (fun x => indicate_nat (Classes.eqb x0 x)) xs) = 0%nat.
Lemma list_sum_indicate {X} `{Finite X} (x0 : X) (xs : list X) : NoDup xs -> In x0 xs -> list_sum (map (fun x => indicate_nat (Classes.eqb x0 x)) xs) = 1%nat.
Lemma vertical_strip {X Y} `{Finite X, Finite Y} (x : X): count (fun p => Classes.eqb x (fst p)) = card Y.
Lemma uniform_fst {X Y} `{Finite X, Finite Y} (d : dist (X * Y)) : uniform d -> uniform (monad_map fst d).
Lemma sigma_dist_equiv {X} `{Finite X} (d : dist X) f : sigma_dist d (fun x q => q * f x) == sigma_dist (normalize d) (fun x q => q * f x).
Lemma uniform_sigma_dist {X} `{Finite X} (d : dist X) f : uniform d -> sigma_dist d (fun x q => q * f x) == Qsum (map f enum) / Q_of_nat (card X).
Lemma eval_correct o : hoare uniform uniform (eval o).
Lemma card_prod {X Y} `{Finite X, Finite Y} : card (X * Y) = (card X * card Y)%nat.
Lemma Q_of_nat_prod (x y : nat) : Q_of_nat (x * y)%nat = Q_of_nat x * Q_of_nat y.
Lemma sumF_ext {X} `{Finite X} (f g : X -> nat) : (forall x, f x = g x) -> sumF f = sumF g.
Lemma double_sum {X Y} (xs : list X) (ys : list Y) (f : X * Y -> nat) : list_sum (map (fun x => list_sum (map (fun y => f (x, y)) ys)) xs) = list_sum (map f (list_prod xs ys)).
Lemma double_sumQ {X Y} (xs : list X) (ys : list Y) (f : X * Y -> Q) : Qsum (map (fun x => Qsum (map (fun y => f (x, y)) ys)) xs) == Qsum (map f (list_prod xs ys)).
Lemma list_sum_map_plus {X} (f g : X -> nat) (xs : list X) : list_sum (map (fun x => f x + g x)%nat xs) = (list_sum (map f xs) + list_sum (map g xs))%nat.
Lemma list_sum_map_flip {X Y} (xs : list X) (ys : list Y) (f : X -> Y -> nat) : list_sum (map (fun x => list_sum (map (f x) ys)) xs) = list_sum (map (fun y => list_sum (map (fun x => f x y) xs)) ys).
Lemma sum_remove : forall (a : nat) (l : list nat), In a l -> (a + list_sum (remove_aux Nat.eqb l a) = list_sum l)%nat.
Lemma list_sum_remove_aux_map {X} `{EqDec X} (a : X) : forall (l : list X) (f : X -> nat), In a l -> (list_sum (map f (remove_aux Classes.eqb l a)) = list_sum (remove_aux Nat.eqb (map f l) (f a)))%nat.
Lemma sum_remove_map {X} `{EqDec X} (a : X) : forall (l : list X) (f : X -> nat), In a l -> (f a + list_sum (map f (remove_aux Classes.eqb l a)))%nat = list_sum (map f l).
Lemma sum_remove_mapQ {X} `{EqDec X} (a : X) : forall (l : list X) (f : X -> Q), In a l -> (f a + Qsum (map f (remove_aux Classes.eqb l a))) == Qsum (map f l).
Lemma list_sum_map_ext {X} `{EqDec X} (f : X -> nat) (l : list X) : forall (l' : list X), NoDup l -> NoDup l' -> (forall x, In x l -> In x l') -> (forall x, In x l' -> In x l) -> list_sum (map f l) = list_sum (map f l').
Lemma list_sum_map_extQ {X} `{EqDec X} (f : X -> Q) (l : list X) : forall (l' : list X), NoDup l -> NoDup l' -> (forall x, In x l -> In x l') -> (forall x, In x l' -> In x l) -> Qsum (map f l) == Qsum (map f l').
Lemma NoDup_list_prod {X Y} (xs : list X) : forall (ys : list Y), NoDup xs -> NoDup ys -> NoDup (list_prod xs ys).
Lemma sum_2D {X Y} `{Finite X, Finite Y} (f : X * Y -> nat) : sumF f = sumF (fun x => sumF (fun y => f (x,y))).
Lemma sumFQ_2D {X Y} `{Finite X, Finite Y} (f : X * Y -> Q) : sumFQ f == sumFQ (fun x => sumFQ (fun y => f (x,y))).
Lemma sum_2D_flip {X Y} `{Finite X, Finite Y} (f : X -> Y -> nat) : sumF (fun x => sumF (f x)) = sumF (fun y => sumF (fun x => f x y)).
Lemma list_sum_indicate_empty {X} `{Finite X} (x0 : X) (xs : list X) : ~ In x0 xs -> list_sum (map (fun x => indicate_nat (Classes.eqb x0 x)) xs) = 0%nat.
Lemma list_sum_indicate {X} `{Finite X} (x0 : X) (xs : list X) : NoDup xs -> In x0 xs -> list_sum (map (fun x => indicate_nat (Classes.eqb x0 x)) xs) = 1%nat.
Lemma vertical_strip {X Y} `{Finite X, Finite Y} (x : X): count (fun p => Classes.eqb x (fst p)) = card Y.
Lemma uniform_fst {X Y} `{Finite X, Finite Y} (d : dist (X * Y)) : uniform d -> uniform (monad_map fst d).