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.

Lemma evalDist_bind_distance_gen:
forall (A B : Set) (c1 c2 : Comp B) (c3 c4 : B -> Comp A) (d : Rat),
well_formed_comp c1 ->
well_formed_comp c2 ->
(forall b, well_formed_comp (c3 b)) ->
(forall b, well_formed_comp (c4 b)) ->
(forall b : B, | evalDist c1 b - evalDist c2 b | <= d) ->
(forall (b : B) (a : A), In b (getSupport c1) -> | evalDist (c3 b) a - evalDist (c4 b) a | <= d) ->
(forall a, In a (getSupport c2) -> In a (getSupport c1)) ->
forall a : A,
| evalDist (x <- c1; c3 x) a - evalDist (x <- c2; c4 x) a | <= (length (getSupport c1) * 3 / 1) * d.