Section RndDup.
Variable eta : nat.
Definition RndDup_G (A : Set)(ls : list A) (x : Bvector eta) :=
rs <-$ compMap _ (fun _ => {0, 1} ^ eta) ls;
ret (if (in_dec (EqDec_dec _) x rs) then true else false).
(* Definition RndDup_G q (x : Bvector eta) := rs <-$ compMap _ (fun _ => {0, 1} ^ eta) (allNatsLt q); ret (if (in_dec (EqDec_dec _) x rs) then true else false). *)
intros.
simpl.
remember (getSupport c1) as ls.
destruct ls.
unfold sumList.
simpl.
assert (Pr  [c1 ] == 0).
eapply getSupport_not_In_evalDist.
rewrite <- Heqls.
simpl.
intuition.
rewrite H.
assert (evalDist c1 false == 0).
eapply getSupport_not_In_evalDist.
rewrite <- Heqls.
simpl.
intuition.
rewrite H0.
repeat rewrite ratMult_0_l.
eapply ratAdd_0_l.
destruct b.
destruct ls.
unfold sumList.
simpl.
rewrite <- ratAdd_0_l.
rewrite ratAdd_0_r at 1.
eapply ratAdd_eqRat_compat.
intuition.
symmetry.
assert (evalDist c1 false == 0).
eapply getSupport_not_In_evalDist.
rewrite <- Heqls.
simpl.
intuition.
rewrite H.
eapply ratMult_0_l.
destruct b.
exfalso.
assert (NoDup (true :: true :: ls))%list.
rewrite Heqls.
eapply getSupport_NoDup.
inversion H; clear H; subst.
simpl in *.
intuition.
destruct ls.
unfold sumList.
simpl.
rewrite <- ratAdd_0_l.
intuition.
destruct b.
assert (NoDup (true :: false :: true :: ls)%list).
rewrite Heqls.
eapply getSupport_NoDup.
inversion H; clear H; subst.
simpl in *.
intuition.
assert (NoDup (true :: false :: false  :: ls)%list).
rewrite Heqls.
eapply getSupport_NoDup.
inversion H; clear H; subst.
inversion H3; clear H3; subst.
simpl in *.
intuition.
destruct ls.
unfold sumList.
simpl.
eapply ratAdd_eqRat_compat; intuition.
assert ( Pr  [c1 ] == 0).
eapply getSupport_not_In_evalDist.
rewrite <- Heqls.
simpl.
intuition.
rewrite H.
rewrite ratMult_0_l.
intuition.
destruct b.
destruct ls.
unfold sumList.
simpl.
rewrite <- ratAdd_0_l.
eapply ratAdd_comm.
destruct b.
assert (NoDup (false :: true :: true :: ls)%list).
rewrite Heqls.
eapply getSupport_NoDup.
inversion H; clear H; subst.
inversion H3; clear H3; subst.
simpl in *.
intuition.
assert (NoDup (false :: true :: false  :: ls)%list).
rewrite Heqls.
eapply getSupport_NoDup.
inversion H; clear H; subst.
simpl in *.
intuition.
assert (NoDup (false :: false  :: ls)%list).
rewrite Heqls.
eapply getSupport_NoDup.
inversion H; clear H; subst.
simpl in *.
intuition.
Qed.
intuition.
rewrite bool_Comp_seq.
assert (Pr  [b2 <-$ c2; ret true || b2 ] == 1).
comp_irr_l.
rewrite evalDist_ret_1; simpl; intuition.
rewrite H0.
clear H0.
assert (Pr  [b2 <-$ c2; ret false || b2 ] == Pr[c2]).
rewrite bool_Comp_seq.
rewrite evalDist_ret_1.
rewrite evalDist_ret_0.
rewrite ratMult_0_r.
rewrite <- ratAdd_0_r.
eapply ratMult_1_r.
simpl.
intuition.
simpl; intuition.
rewrite H0.
clear H0.
rewrite ratMult_1_r.
intuition.
Qed.
intuition.
symmetry.
rewrite <-(@evalDist_right_ident _ eqd).
comp_skip.
simpl.
repeat match goal with
|- context [ if ?X then _ else _ ] => destruct X
end; rewrite ?@eqb_leibniz in *; reflexivity || congruence.
Qed.
intuition.
rewrite bool_Comp_seq.
eapply ratAdd_leRat_compat.
eapply leRat_trans.
eapply ratMult_leRat_compat.
eapply leRat_refl.
eapply evalDist_le_1.
eapply eqRat_impl_leRat.
eapply ratMult_1_r.
eapply leRat_trans.
eapply ratMult_leRat_compat.
eapply evalDist_le_1.
eapply leRat_refl.
rewrite ratMult_1_l.
unfold orb.
rewrite evalDist_right_ident.
intuition.
Qed.
intuition.
rattac.
rewrite mult_plus_distr_r.
f_equal.
eapply mult_assoc.
Qed.

Theorem RndDup_P :
forall (A : Set)(ls : list A) x,
Pr [RndDup_G _ ls x] <= (length ls) / expnat 2 eta.