Section EagerSampling.
Variable v_firstn : forall n1 n2, Bvector (n1 + n2)%nat -> Bvector n1.
Variable v_skipn : forall n1 n2, Bvector (n1 + n2)%nat -> Bvector n2.
Hypothesis v_firstn_correct : forall n1 n2 v1 v2,  (v_firstn n1 n2 (VectorDef.append v1 v2)) = v1.
Hypothesis v_skipn_correct : forall n1 n2 v1 v2,  (v_skipn n1 n2 (VectorDef.append v1 v2)) = v2.
Hypothesis firstn_skipn_correct : forall n1 n2 (v : Bvector (n1 + n2)), v = (VectorDef.append (v_firstn n1 n2 v) (v_skipn n1 n2 v)).
intuition.
eapply det_eq_impl_dist_sem_eq;
wftac.
unfold DetSem.evalDet_equiv.
intuition.
Admitted.
Admitted.
induction 1; intuition.
exists O.
exists (fun v => a).
intuition.
eapply leRat_trans.
eapply eqRat_impl_leRat.
rewrite <- ratIdentityIndiscernables.
eapply evalDist_Bind_1; intuition; wftac.
simpl.
destruct (EqDec_dec eqd a a0); destruct (pf a a0); subst; intuition.
eapply rat0_le_all.
assert (nz (length (getSupport c1))).
econstructor.
eapply getSupport_length_nz.
trivial.
destruct (IHwell_formed_comp (comp_EqDec c1) (d * (1 / (length (getSupport c1))) * (1/3))).
destruct H3.
intuition.
assert (forall (d : Rat) (b : B),
In b (getSupport c1) ->
exists (t : nat) (f : Bvector t -> A),
(forall a : A,
| evalDist (v <- { 0 , 1 }^t; ret f v) a - evalDist (c2 b) a | <= d) /\
(forall a : A,
In a (getSupport (v <- { 0 , 1 }^t; ret f v)) ->
In a (getSupport (c2 b)))).
intuition.
clear H1.
specialize (H3 (d * (1 / (length (getSupport c1))) * (1/3))).
(* assert (forall b : B, In b (getSupport c1) -> exists (t : nat), forall t', t' >= t -> exists (f : Bvector t' -> A), forall a : A, evalDist (v <- { 0 , 1 }^t'; ret f v) a == evalDist (c2 b) a). intuition.    Lemma maxWitness : forall (A : Set)(P_A : A -> Prop)(P : A -> nat -> Prop), (forall (a : A), P_A a -> exists (b : nat), forall b', b' >= b -> P a b') -> exists max, forall a, P_A a -> P a max. Admitted.  *)
assert (exists t, forall b, In b (getSupport c1) -> exists (f : Bvector t -> A),
(forall a, | evalDist (v <- {0, 1} ^ t; ret f v) a - evalDist (c2 b) a | <= (d * (1 / (length (getSupport c1))) * (1/3))) /\
(forall a : A,
In a (getSupport (v <- { 0 , 1 }^t; ret f v)) ->
In a (getSupport (c2 b)))).
(* find max over all b in support of c1 *)
admit.
clear H3.
destruct H1.
exists (x + x1)%nat.
Admitted.
Show.
apply witnessMap in H1.
destruct H1.
exists (fun v => let b := x0 (v_firstn x x1 v) in x2 b (v_skipn x x1 v)).
intuition.
specialize (sample_split (fun v1 v2 => ret (x2 (x0 v1) v2))); intuition.
rewrite H3.
assert (forall (eqdb : eq_dec B)(eqda : eq_dec A), evalDist (v1 <- { 0 , 1 }^x; v2 <- { 0 , 1 }^x1; Ret eqda (x2 (x0 v1) v2)) a ==
evalDist (b <- (v1 <- { 0 , 1 }^x; Ret eqdb (x0 v1)); v2 <- { 0 , 1 }^x1; Ret eqda (x2 b v2)) a).
intuition.
comp_inline 1%nat O.
comp_skip.
symmetry.
eapply eqRat_trans.
intuition.
simpl.
unfold sumList.
simpl.
destruct (eqd b b).
rewrite <- ratAdd_0_l.
rewrite ratMult_1_l.
intuition.
congruence.
Qed.
eapply evalDist_left_ident'.
comp_simp.
comp_ute.
rewrite H6.
induction ls; intuition.
unfold sumList; simpl.
eapply leRat_trans.
eapply eqRat_impl_leRat.
rewrite <- ratIdentityIndiscernables.
intuition.
eapply rat0_le_all.
simpl in *.
repeat rewrite sumList_cons.
rewrite rat_distance_of_sum.
rewrite IHls; intuition.
assert (S (length ls) = 1 + (length ls))%nat.
omega.
rewrite H0.
rewrite ratAdd_num.
eapply leRat_trans.
Focus 2.
eapply eqRat_impl_leRat.
rewrite ratMult_distrib_r.
rewrite ratMult_1_l.
eapply eqRat_refl.
eapply ratAdd_leRat_compat; intuition.
Qed.
intuition.
simpl.
erewrite (sumList_subset _ _ _ _ H5).
eapply leRat_trans.
eapply sumList_ratDistance; intuition.
eapply ratDistance_ratMult_le.
eapply H3.
eapply H4.
trivial.
eapply evalDist_le_1; intuition.
eapply comp_eq_dec; trivial.
eapply evalDist_le_1; intuition.
eapply bind_eq_dec; eauto.
eapply evalDist_le_1; intuition.
eapply bind_eq_dec; eauto.
eapply evalDist_le_1; intuition.
eapply bind_eq_dec; eauto.
rewrite <- ratMult_assoc.
rewrite <- ratMult_num_den.
eapply ratMult_leRat_compat; intuition.
eapply eqRat_impl_leRat.
eapply eqRat_terms.
omega.
simpl.
trivial.
intuition.
rewrite ratMult_0.
left.
eapply getSupport_not_In_evalDist.
intuition.
Grab Existential Variables.
eapply getSupport_NoDup.
eapply getSupport_NoDup.
eapply comp_eq_dec; trivial.
Qed.
eapply leRat_trans.
rewrite ratDistance_comm.
eapply evalDist_bind_distance_gen; intuition; wftac.
admit.
rewrite ratDistance_comm.
eapply H4.
rewrite ratDistance_comm.
eapply H1.
trivial.
admit.
intuition.
wftac.
repeat simp_in_support.
eapply getSupport_In_Bind.
eapply H5.
eapply getSupport_In_Bind.
simpl.
eapply in_getAllBvectors.
simpl.
intuition.
eapply H1.
eapply H5.
eapply getSupport_In_Bind.
simpl.
eapply in_getAllBvectors.
simpl.
intuition.
eapply getSupport_In_Bind.
simpl.
eapply in_getAllBvectors.
simpl.
intuition.
exists n.
exists (fun x => x).
intuition.
eapply leRat_trans.
eapply eqRat_impl_leRat.
rewrite <- ratIdentityIndiscernables.
eapply evalDist_right_ident.
eapply rat0_le_all.
simpl.
eapply in_getAllBvectors.
destruct (IHwell_formed_comp eqd d).
destruct H1.
intuition.
Admitted.
Inductive monte_carlo : forall (A : Set), (Comp A) -> Prop :=
| monte_carlo_ret : forall (A : Set)(eqd : eq_dec A) a,
monte_carlo (Ret eqd a)
| monte_carlo_rnd : forall (n : nat),
monte_carlo (Rnd n)
| monte_carlo_bind : forall (A B : Set)(c : Comp B)(f : B -> Comp A),
monte_carlo c ->
(forall b, In b (getSupport  c) -> monte_carlo (f b)) ->
monte_carlo (Bind c f).

Lemma eager_sampling_strong : forall (A : Set)(eqd : EqDec A)(c : Comp A),
monte_carlo c ->
exists t (f : Bvector t -> A),
forall a,
evalDist (v <- {0, 1}^t; ret (f v)) a == evalDist c a.