Section ListHybrid.
Variable A B C S_A : Set.
Hypothesis eqdb : EqDec B.
Variable defA : A.
Variable A1 : Comp (list A * S_A).
Variable A2 : S_A -> A -> Comp B.
Variable A2' :  S_A -> A -> Comp B.
Variable A3 : S_A -> list B -> Comp C.
Hypothesis A1_wf : well_formed_comp A1.
Hypothesis A2_wf :  forall x y, well_formed_comp (A2 x y).
Hypothesis A2'_wf : forall x y, well_formed_comp (A2' x y).
Variable numA : nat.
Hypothesis numA_correct :
forall lsa s,
In (lsa, s) (getSupport A1) ->
length lsa = numA.
Definition LH_G0  :=
[lsa, s_A] <-$2 A1;
lsb <-$ compMap _ (A2 s_A) lsa;
A3 s_A lsb.
Definition LH_G1 :=
[lsa, s_A] <-$2 A1;
lsb <-$ compMap _ (A2' s_A) lsa;
A3 s_A lsb.
Definition LH_Gn n :=
[lsa, s_A] <-$2 A1;
lsa1 <- firstn n lsa;
lsa2 <- skipn n lsa;
lsb1 <-$ compMap _ (A2' s_A) lsa1;
lsb2 <-$ compMap _ (A2 s_A) lsa2;
A3 s_A (lsb1 ++ lsb2).
Definition LH_G_0  n :=
[lsa, s_A] <-$2 A1;
lsa1 <- firstn n lsa;
a <- nth n lsa defA;
lsa2 <- skipn (S n) lsa;
lsb1 <-$ compMap _ (A2' s_A) lsa1;
b <-$ A2 s_A a;
lsb2 <-$ compMap _ (A2 s_A) lsa2;
A3 s_A (lsb1 ++ (b :: lsb2)).
Definition LH_G_1  n :=
[lsa, s_A] <-$2 A1;
lsa1 <- firstn n lsa;
a <- nth n lsa defA;
lsa2 <- skipn (S n) lsa;
lsb1 <-$ compMap _ (A2' s_A) lsa1;
b <-$ A2' s_A a;
lsb2 <-$ compMap _ (A2 s_A) lsa2;
A3 s_A (lsb1 ++ (b :: lsb2)).
Variable F : nat -> Rat.
Local Opaque evalDist.
induction x; intuition; simpl in *.
rewrite plus_0_r.
eapply leRat_trans.
eapply eqRat_impl_leRat.
rewrite <- ratIdentityIndiscernables.
intuition.
eapply rat0_le_all.
eapply leRat_trans.
eapply ratDistance_le_trans.
eapply H.
assert (n + S x = S n + x)%nat.
omega.
rewrite H0.
clear H0.
eapply IHx.
rewrite map_app.
simpl.
(* eapply eqRat_impl_leRat. rewrite ratS_num. rewrite ratMult_distrib_r. eapply ratAdd_eqRat_compat; intuition. symmetry. eapply ratMult_1_l. *)
(* 1 subgoal, subgoal 1 (ID 390) *)
(*   A, B, C, S_A : Set *)
(*   eqdb : EqDec B *)
(*   defA : A *)
(*   A1 : Comp (list A * S_A) *)
(*   A2, A2' : S_A -> A -> Comp B *)
(*   A3 : S_A -> list B -> Comp C *)
(*   A1_wf : well_formed_comp A1 *)
(*   A2_wf : forall (x : S_A) (y : A), well_formed_comp (A2 x y) *)
(*   A2'_wf : forall (x : S_A) (y : A), well_formed_comp (A2' x y) *)
(*   numA : nat *)
(*   numA_correct : forall (lsa : list A) (s : S_A), *)
(*                  In (lsa, s) (getSupport A1) -> length lsa = numA *)
(*   F : nat -> Rat *)
(*   H : forall (n : nat) (c : C), *)
(*       | evalDist (LH_Gn n) c - evalDist (LH_Gn (S n)) c | <= F n *)
(*   x : nat *)
(*   IHx : forall (n : nat) (c : C), *)
(*         | evalDist (LH_Gn n) c - evalDist (LH_Gn (n + x)) c | <= *)
(*         sumList (map (Init.Nat.add n) (allNatsLt x)) F *)
(*   n : nat *)
(*   c : C *)
(*   ============================ *)
(*   F n + sumList (map (fun m : nat => S (n + m)) (allNatsLt x)) F <= *)
(*   sumList (map (Init.Nat.add n) (allNatsLt x) ++ (n + x)%nat :: nil) F *)
(* (dependent evars: (printing disabled) ) *)
Admitted.
induction ls; intuition; simpl in *.
destruct n; simpl in *; trivial.
destruct n; simpl in *.
omega.
eapply IHls.
omega.
Qed.
intuition.
unfold LH_Gn, LH_G_0.
comp_skip; comp_simp.
comp_skip.
erewrite skipn_S.
simpl.
inline_first.
comp_skip.
reflexivity.
inline_first.
comp_skip.
erewrite numA_correct; intuition; eauto.
Qed.
intuition.
unfold LH_Gn, LH_G_1.
comp_skip.
comp_simp.
rewrite (firstn_S _ defA).
assert (evalDist (lsb1 <-$ (foreach  (x in firstn n l ++ nth n l defA :: nil) A2' s x);
lsb2 <-$ (foreach  (x in skipn (S n) l)A2 s x); A3 s (lsb1 ++ lsb2) ) c ==
evalDist (lsb1 <-$ (r1 <-$ compMap _ (A2' s) (firstn n l);
r2 <-$ compMap _ (A2' s) (nth n l defA :: nil);
ret (r1 ++ r2));
lsb2 <-$ (foreach  (x in skipn (S n) l)A2 s x); A3 s (lsb1 ++ lsb2) ) c
).
comp_skip.
eapply compMap_app.
match goal with [H1:_|- _ ] => rewrite H1; clear H1 end.
inline_first.
comp_skip.
inline_first.
comp_skip.
inline_first.
comp_skip.
reflexivity.
rewrite <- app_assoc.
rewrite <- app_comm_cons.
simpl.
intuition.
erewrite numA_correct; intuition; eauto.
Qed.

Theorem list_hybrid_close :
forall k c,
(forall n c, n < numA -> | (evalDist (LH_G_0 n) c) - (evalDist (LH_G_1 n) c) | <= k) ->
| (evalDist (LH_G0) c) - (evalDist (LH_G1) c) | <= (numA)/1 * k.