Section RandPermSwitching.
Variable A D R : Set.
Variable RndR : Comp R.
Hypothesis RndR_wf : well_formed_comp RndR.
Variable A2 : OracleComp D R bool.
Hypothesis eqdd : EqDec D.
Hypothesis eqdr : EqDec R.
Variable fBad : list (D * R) -> D -> R -> bool.
Variable badProb : nat -> Rat.
Hypothesis badProb_mono : forall n1 n2, (n1 <= n2)%nat -> badProb n1 <= badProb n2.
Hypothesis A2_wf : well_formed_oc A2.
Variable A2_queries : nat.
Hypothesis A2_queries_correct : queries_at_most' A2 A2_queries.
Hypothesis badProb_correct :
forall d f,
Pr [r <-$ RndR;
ret (fBad f d r)] <= badProb (S (length f)).
Hypothesis goodExists :
forall d f,
(length f <= A2_queries) %nat ->
exists r,
In r (getSupport RndR) /\
fBad f d r = false.
(* Hypothesis fBad_single : forall d r, fBad ((d, r) :: nil) = false. *)
(* Hypothesis goodExists : forall d f, arrayLookup _ f d = None -> exists r, In r (getSupport RndR) /\ fBad f d r = false. *)
Definition rndNotBad(d : D)(f : list (D * R)):=
Repeat RndR (fun r => negb (fBad f d r)).
Definition GenRP(s : list (D * R))(d : D) : Comp (R * list (D * R)) :=
match arrayLookup _ s d with
| Some r => ret (r, s)
| None => r <-$ (rndNotBad d s); ret (r, (d, r) :: s)
end.
Definition RPS_G0  :=
[b, _] <-$2 A2 _ _ (@randomFunc D R RndR _ ) nil;
ret b.
Definition RPS_G1 :=
[b, _] <-$2 A2 _ _ GenRP nil;
ret b.
Definition randomFunc_bad (s : list (D * R) * bool) d :=
[s, bad] <-2 s;
match (arrayLookup _ s d) with
| Some r => ret (r, (s, bad))
| None =>
r <-$ RndR;
newF <- ((d, r) :: s);
bad' <- fBad s d r;
ret (r, (newF, bad || bad'))
end.
Definition GenRP_bad (s : list (D * R) * bool) d :=
[s, bad] <-2 s;
match (arrayLookup _ s d) with
| Some r => ret (r, (s, bad))
| None =>
r <-$ RndR;
newF <- ((d, r) :: s);
bad' <- fBad s d r;
if (bad') then
(r <-$ rndNotBad d s;
ret (r, ((d, r) :: s, bad || bad')))
else
ret (r, (newF, bad || bad'))
end.
Definition RPS_G_1 :=
[b, s] <-$2 A2 _ _ (randomFunc_bad) (nil, false);
ret (b, snd s).
Definition RPS_G_2 :=
[b, s] <-$2 A2 _ _ (GenRP_bad) (nil, false);
ret (b, snd s).
intuition.
unfold randomFunc_bad.
destruct (arrayLookup eqdd a0 b0); wftac.
Qed.
intuition.
simpl in *.
case_eq (arrayLookup eqdd a0 b0); intuition; wftac.
unfold rndNotBad; wftac.
edestruct goodExists ; eauto.
intuition.
econstructor.
unfold eq_dec; intuition.
eapply (EqDec_dec _).
trivial.
eapply filter_In; intuition.
eauto.
rewrite H4.
trivial.
Qed.
eapply comp_spec_consequence.
eapply (@oc_comp_spec_eq_until_bad _ _ _ _ _ _ _ _ _ _ _ _ _
(fun a => snd a)
(fun a => snd a)
(fun a b => (fst a = fst b))).
intros.
eapply randomFunc_bad_wf.
intros.
eapply GenRP_bad_wf.
admit.
intuition.
simpl in *.
subst.
case_eq (arrayLookup eqdd a0 a1); intuition.
eapply comp_spec_ret; intuition.
comp_skip.
eapply comp_base_exists; eauto.
eapply comp_base_exists; eauto.
destruct ( fBad a0 a1 b) eqn:?.
comp_irr_r.
unfold rndNotBad.
edestruct goodExists.
eauto.
admit.
econstructor.
unfold eq_dec; intuition.
eapply (EqDec_dec _).
trivial.
eapply filter_In; intuition.
eauto.
match goal with H5:_|-_ => rewrite H5; reflexivity end.
eapply comp_spec_ret.
simpl.
split.
intuition.
intros.
rewrite orb_true_r in *.
discriminate.
eapply comp_spec_ret; intuition.
intuition.
simpl in *.
case_eq (arrayLookup eqdd a1 d); intuition.
rewrite H1 in H0.
repeat simp_in_support.
trivial.
rewrite H1 in H0.
repeat simp_in_support.
trivial.
intuition.
simpl in *.
case_eq (arrayLookup eqdd a1 d ); intuition;
rewrite H1 in H0;
repeat simp_in_support;
trivial.
trivial.
trivial.
intuition.
Grab Existential Variables.
admit.
admit.
trivial.
Admitted.
unfold RPS_G_1, RPS_G_2.
inline_first.
eapply comp_spec_impl_eq.
comp_skip.
eapply rf_rp_oc_eq_until_bad.
intuition.
simpl in *.
intuition.
destruct b.
simpl in *.
destruct p; simpl in *.
subst.
comp_simp.
simpl.
eapply comp_spec_ret; intuition.
Qed.
intuition.
unfold RPS_G_1, RPS_G_2.
eapply comp_spec_impl_eq.
comp_skip.
eapply rf_rp_oc_eq_until_bad.
intuition.
simpl in *.
intuition.
destruct b.
simpl in *.
destruct p; simpl in *.
eapply comp_spec_ret; intuition.
pairInv.
subst.
intuition.
subst.
intuition.
subst.
pairInv.
intuition.
subst.
trivial.
Qed.
unfold RPS_G_1.
inline_first.
assert (Pr
[a <-$
A2 (list (D * R) * bool)%type _
(randomFunc_bad) (nil, false);
x <-$ ([b, s]<-2 a; ret (b, snd s)); ret snd x ]
==
Pr
[a <-$
A2 (list (D * R) * bool)%type _
(randomFunc_bad) (nil, false);
ret snd (snd a) ]
).
comp_skip.
comp_simp.
reflexivity.
rewrite H.
clear H.
eapply leRat_trans.
eapply (@oc_eventProb_0_1 _ (fun p => length (fst p)) _ badProb).
eauto.
eapply badProb_mono.
trivial.
intuition.
simpl in *.
subst.
case_eq (arrayLookup eqdd a a0); intuition.
comp_simp.
simpl.
rewrite evalDist_ret_0.
eapply rat0_le_all.
congruence.
simpl in *.
eapply leRat_trans.
2:{
eapply badProb_correct.
}
inline_first.
comp_skip.
simpl.
eapply leRat_refl.
intuition.
simpl in *.
destruct (arrayLookup eqdd a a1);
repeat simp_in_support.
omega.
simpl.
intuition.
trivial.
intuition.
Qed.

Theorem RPS_G_1_2_close :
| Pr[x <-$ RPS_G_1; ret fst x] - Pr[x <-$ RPS_G_2; ret fst x] | <= (A2_queries / 1)  * badProb A2_queries.