Section DistSingle_impl_Mult.
Variable A B : Set.
Variable A_EqDec : EqDec A.
Variable B_EqDec : EqDec B.
Variable c1 c2 : A -> Comp B.
Variable A_State : Set.
Variable A_State_EqDec : EqDec A_State.
Variable A1 : Comp (A * A_State).
Variable A2 : A_State -> list B -> Comp bool.
Hypothesis c1_wf : forall a, well_formed_comp (c1 a).
Hypothesis c2_wf : forall a, well_formed_comp (c2 a).
(* Produce a list of length n derived from c1, and c2.  The first i values come from c1, and the rest come from c2. *)
Definition computeHybrid(n i : nat) a : Comp (list B) :=
b1 <-$ compMap _ (fun _ => (c1 a)) (forNats i);
b2 <-$ compMap _ (fun _ => (c2 a)) (forNats (minus n i));
ret (b1 ++ b2).
Variable n : nat.
Hypothesis n_pos : n > 0.
induction n; destruct i; intuition; try omega.
unfold computeHybrid.
unfold minus.
fold minus.
rewrite <- minus_n_O.
unfold forNats.
fold forNats.
unfold compMap.
fold compMap.
inline_first.
comp_skip.
inline_first.
comp_simp.
comp_irr_l.
inline_first.
comp_skip.
simpl.
intuition.
unfold computeHybrid.
unfold minus.
fold minus.
unfold forNats.
fold forNats.
unfold compMap.
fold compMap.
inline_first.
do 2 comp_at comp_inline leftc 1%nat.
comp_swap_l.
comp_skip.
assert
(evalDist
(a1 <-$
(lsb' <-$
(b <-$ (c1 a);
lsb' <-$ compMap B_EqDec (fun _ : nat => (c1 a)) (forNats i);
ret b :: lsb'); ret x0 :: lsb');
a2 <-$ compMap B_EqDec (fun _ : nat => (c2 a)) (forNats (n0 - S i));
ret a1 ++ a2) x ==
evalDist
(ls <-$ (computeHybrid n0 (S i) a);
ret (x0 :: ls)) x).
unfold computeHybrid.
unfold forNats.
fold forNats.
unfold compMap.
fold compMap.
inline_first.
comp_skip.
inline_first.
comp_skip.
comp_simp.
inline_first.
comp_skip.
comp_simp.
simpl.
intuition.
rewrite H1.
clear H1.
eapply eqRat_trans.
2:{
comp_skip.
eapply eqRat_refl.
}
unfold computeHybrid.
inline_first.
comp_skip.
inline_first.
comp_skip.
inline_first.
comp_skip.
comp_simp.
simpl.
intuition.
Qed.

Theorem hybrid_replace_c2_equiv :
forall i x a,
i < n ->
evalDist
(b <-$ (c2 a);
hybrid <-$ computeHybrid n i a;
ret (listReplace hybrid i b b)) x ==
evalDist (computeHybrid n i a) x.