Section DistMult_impl_RepeatCore.
Variable A B : Set.
Hypothesis B_EqDec : EqDec B.
Variable P : B -> bool.
Variable c1 c2 : A -> Comp B.
Variable A_State : Set.
Variable A1 : Comp (A * A_State).
Variable A2 : A_State -> B -> Comp bool.
Hypothesis A1_wf : well_formed_comp A1.
Hypothesis A2_wf : forall s_A b, well_formed_comp (A2 s_A b).
Hypothesis c1_wf : forall a s_A, In (a, s_A) (getSupport A1) -> well_formed_comp (c1 a).
Hypothesis c1_repeat_wf : forall a s_A, In (a, s_A) (getSupport A1) -> exists b, In b (filter P (getSupport (c1 a))).
Hypothesis c2_wf : forall a s_A, In (a, s_A) (getSupport A1) -> well_formed_comp (c2 a).
Hypothesis c2_repeat_wf : forall a s_A, In (a, s_A) (getSupport A1) -> exists b, In b (filter P (getSupport (c2 a))).
Variable n : nat.
(* Assume A1 can effectively distinguish the cores as in RepeatCore_G, construct an adversary B that can distinguish the entire distributions given multiple samples as in DistMult_G. *)
Definition DM_RC_G1(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
p <-$ Repeat (b <-$ (c a); g <-$ (A2 s_A b); ret (b, g)) (fun p => P (fst p));
ret (snd p).
intuition.
unfold RepeatCore_G, DM_RC_G1.
comp_skip.
comp_simp.
assert (evalDist (b0 <-$ Repeat (c a) P; A2 a0 b0) x
==
evalDist (p <-$ (b0 <-$ Repeat (c a) P; b <-$ A2 a0 b0; ret (b0, b)); ret (snd p)) x).
inline_first.
comp_skip.
inline_first.
rewrite <- evalDist_right_ident.
comp_skip.
comp_simp.
simpl.
reflexivity.
rewrite H2.
comp_skip.
eapply repeat_fission; intuition.
eauto.
eauto.
Qed.
Definition DM_RC_G2(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
p <-$ Repeat (b <-$ (c a); g <-$ (A2 s_A b); ret (b, g)) (fun p => P (fst p));
ret (Some (snd p)).
intuition.
unfold DM_RC_G1, DM_RC_G2.
comp_skip.
comp_simp.
comp_skip.
dist_compute.
Qed.
Definition DM_RC_G3(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
ls <-$ compMap _ (fun _ => b <-$ c a; g <-$ (A2 s_A b); ret (b, g)) (forNats n);
ret hd_error (map (fun x => snd x) (filter (fun p => P (fst p)) ls)).
intuition.
unfold DM_RC_G2, DM_RC_G3.
eapply evalDist_bind_distance; intuition.
rewrite ratDistance_comm.
eapply leRat_trans.
eapply compMap_Repeat_close.
wftac.
edestruct H0.
eauto.
apply filter_In in H3.
intuition.
specialize (A2_wf b0 x0).
apply well_formed_val_exists in A2_wf.
destruct A2_wf.
econstructor.
eapply filter_In.
intuition.
eapply getSupport_In_Seq.
eauto.
eapply getSupport_In_Seq.
eauto.
simpl.
intuition.
simpl.
trivial.
eapply expRat_leRat_compat.
eapply leRat_trans.
2:{
eapply H1.
eauto.
}
comp_inline_l.
comp_skip.
inline_first.
comp_irr_l.
simpl.
intuition.
Qed.
Definition DM_RC_G4(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
allB <-$ compMap _ (fun _ => (c a)) (forNats n);
allB_G <-$ compMap _ (fun b => g <-$ (A2 s_A b); ret (b, g)) allB;
ret hd_error (map (fun x => snd x) (filter (fun p => P (fst p)) allB_G)).
intuition.
unfold DM_RC_G3, DM_RC_G4.
comp_skip.
symmetry.
comp_simp.
rewrite <- evalDist_assoc; intuition.
comp_skip.
eapply comp_spec_eq_impl_eq.
eapply (@compMap_fission_eq _ _ _ _ _ _ _ _ _ _ _ _ eq); intuition.
simpl.
eapply comp_spec_eq_refl.
subst.
simpl.
eapply eq_impl_comp_spec_eq.
intuition.
comp_at comp_inline rightc 1%nat.
comp_swap_r.
inline_first.
comp_skip.
comp_skip.
comp_simp.
intuition.
Qed.
Definition DM_RC_G5(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
allB <-$ compMap _ (fun _ => (c a)) (forNats n);
allG <-$ compMap _ (A2 s_A) (filter P allB);
ret hd_error allG.
intuition.
unfold DM_RC_G4, DM_RC_G5.
comp_skip.
comp_simp.
comp_skip.
symmetry.
eapply eqRat_trans.
comp_skip.
eapply compMap_filter.
intuition.
eapply eqRat_refl.
inline_first.
comp_skip.
dist_compute.
Qed.
Definition DM_RC_G6(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
opt_b' <-$ (
b <-$ compMap B_EqDec (fun _ : nat => (c a)) (forNats n);
ret head (filter P b));
match opt_b' with
| Some b' => A2 s_A b'
| None => ret false
end.

Theorem DM_RC_G6_equiv :
forall (c : A -> Comp B),
evalDist (DM_RC_G5 c) (Some true) ==
evalDist (DM_RC_G6 c) true.