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.

Theorem rf_rp_oc_eq_until_bad :
comp_spec
(fun y1 y2 =>
snd (snd y1) = snd (snd y2) /\
(snd (snd y1) = false -> fst (snd y1) = fst (snd y2) /\ fst y1 = fst y2))
(A2 (list (D * R) * bool)%type _
randomFunc_bad (nil, false))
(A2 (list (D * R) * bool)%type _
GenRP_bad (nil, false)).