Library ZFiso

Require Import basic ZF ZFpairs ZFsum ZFrelations.
Require Import ZFcont.
Require Import ZFord ZFfix ZFfunext ZFfixrec.
Require Import ZFfixfun.

Set Implicit Arguments.

Isomorphisms


Record iso_fun X Y f : Prop := {
  iso_funm : ext_fun X f;
  iso_typ : typ_fun f X Y;
  iso_inj : x x', x X -> x' X -> f x == f x' -> x == x';
  iso_surj : y, y Y -> exists2 x, x X & f x == y
}.

Lemma iso_fun_morph : X X' Y Y' f f',
  X == X' ->
  Y == Y' ->
  eq_fun X f f' ->
  iso_fun X Y f -> iso_fun X' Y' f'.
constructor; intros.
 symmetry in H1; apply eq_fun_ext in H1.
 do 2 red; intros.
 rewrite <- H in H3; auto.

 red; intros.
 rewrite <- H in H3; rewrite <- H0; rewrite <- (H1 x x H3 (reflexivity _)).
 apply (iso_typ H2); trivial.

 rewrite <- H in H3, H4.
 apply (iso_inj H2); trivial.
 rewrite (H1 x x H3 (reflexivity _)); rewrite (H1 x' x' H4 (reflexivity _)); trivial.

 rewrite <- H0 in H3.
 destruct (iso_surj H2) with y; trivial.
 exists x.
  rewrite <- H; trivial.

  rewrite <- (H1 x x H4 (reflexivity _)); trivial.
Qed.

Lemma iso_change_rhs : X Y Y' f,
  Y == Y' ->
  iso_fun X Y f ->
  iso_fun X Y' f.
intros.
destruct H0 as (fm,tyf,injf,surjf); constructor; intros; eauto.
 rewrite <- H; auto.
rewrite <- H in H0; auto.
Qed.

Lemma eq_iso_fun : X Y f, X == Y -> ( x, x X -> f x == x) ->
  iso_fun X Y f.
constructor; intros.
 do 2 red; intros.
 rewrite H0; trivial.
 rewrite H2; symmetry; apply H0.
 rewrite <- H2; trivial.

 red; intros.
 rewrite H0; trivial.
 rewrite <- H; trivial.

 rewrite H0 in H3; trivial.
 rewrite H3; auto.

 rewrite <- H in H1.
 eauto.
Qed.

Lemma id_iso_fun : X, iso_fun X X (fun x => x).
intros.
apply eq_iso_fun; auto with *.
Qed.

Inverse and symmetry

Definition iso_inv X f y := union (subset X (fun x => f x == y)).

Instance iso_inv_morph0 : A f, morph1 (iso_inv A f).
do 2 red; intros.
unfold iso_inv.
apply union_morph.
apply subset_ext; intros.  apply subset_intro; trivial.
 rewrite H; trivial.

 apply subset_elim1 in H0; trivial.

 apply subset_elim2 in H0; destruct H0.
 rewrite H in H1; eauto.
Qed.

Lemma iso_inv_ext A A' f f' x x' :
  A == A' ->
  eq_fun A f f' ->
  x == x' ->
  iso_inv A f x == iso_inv A' f' x'.
intros.
unfold iso_inv.
apply union_morph.
apply subset_morph; intros; trivial.
red; intros.
rewrite <- H1; rewrite (H0 _ _ H2 (reflexivity _)); reflexivity.
Qed.

Instance iso_inv_morph : Proper (eq_set ==> (eq_set ==> eq_set) ==> eq_set ==> eq_set) iso_inv.
do 4 red; intros.
unfold iso_inv.
apply union_morph; apply subset_morph; trivial.
red; intros.
rewrite (H0 _ _ (reflexivity _)); rewrite H1; reflexivity.
Qed.

Lemma iso_inv_eq : X Y f y,
   iso_fun X Y f -> y Y -> f (iso_inv X f y) == y.
destruct 1; intros.
unfold iso_inv.
destruct iso_surj0 with y; trivial.
refine (transitivity _ _);
 [symmetry; apply iso_funm0;
  [|symmetry;apply union_subset_singl with (y:=x)(y':=x); auto with *]|];
 auto with *.
intros.
apply iso_inj0; trivial.
transitivity y; auto with *.
Qed.

Lemma iso_inv_eq2 : X Y f x,
   iso_fun X Y f -> x X -> iso_inv X f (f x) == x.
destruct 1; intros.
unfold iso_inv.
rewrite union_subset_singl with (y:=x) (y':=x); auto with *.
intros.
apply iso_inj0; trivial.
transitivity (f x); auto with *.
Qed.

Lemma iso_inv_typ : X Y f y,
   iso_fun X Y f -> y Y -> iso_inv X f y X.
destruct 1; intros.
unfold iso_inv.
destruct iso_surj0 with y; trivial.
rewrite union_subset_singl with (y:=x) (y':=x); auto with *.
intros.
apply iso_inj0; trivial.
transitivity y; auto with *.
Qed.

Lemma iso_fun_sym : X Y f, iso_fun X Y f -> iso_fun Y X (iso_inv X f).
constructor; intros.
 do 2 red; intros.
 apply union_morph; apply subset_morph; auto with *.
 red; intros.
 rewrite H1; reflexivity.

 red; intros.
 apply iso_inv_typ with (1:=H); trivial.

 apply (iso_funm H) in H2.
  rewrite iso_inv_eq with (1:=H) in H2; trivial.
  rewrite iso_inv_eq with (1:=H) in H2; trivial.

  apply iso_inv_typ with (1:=H); trivial.

 exists (f y); auto.
  apply (iso_typ H); trivial.

  apply iso_inv_eq2 with (1:=H); trivial.
Qed.

Composition and transitivity

Lemma iso_fun_trans_eq : X Y Z f g h,
  ( x, x X -> g (f x) == h x) ->
  iso_fun X Y f ->
  iso_fun Y Z g ->
  iso_fun X Z h.
intros.
constructor; intros.
 do 2 red; intros.
  rewrite <- H; trivial.
  rewrite <- H.
  2:rewrite <- H3; trivial.
  apply (iso_funm H1).
   apply (iso_typ H0); trivial.

   apply (iso_funm H0); trivial.

 red; intros.
 rewrite <- H; trivial.
 apply (iso_typ H1).
 apply (iso_typ H0); trivial.

 do 2 (rewrite <- H in H4; trivial).
 apply (iso_inj H1) in H4.
  apply (iso_inj H0) in H4; trivial.

  apply (iso_typ H0); trivial.
  apply (iso_typ H0); trivial.

 destruct (iso_surj H1 H2).
 destruct (iso_surj H0 H3).
 exists x0; trivial.
 rewrite <- H; auto.
 generalize (iso_funm H1); intro.
 refine (transitivity _ _);[apply (iso_funm H1);[|apply H6]|]; trivial.
 apply (iso_typ H0); trivial.
Qed.

Definition comp_iso (f:set->set) (g:set->set) := fun x => g (f x).

Lemma iso_fun_trans : X Y Z f g, iso_fun X Y f -> iso_fun Y Z g ->
  iso_fun X Z (comp_iso f g).
unfold comp_iso; intros.
apply iso_fun_trans_eq with Y f g; auto with *.
Qed.

Lemma comp_iso_morph : Proper ((eq_set ==> eq_set) ==> (eq_set ==> eq_set) ==> eq_set ==> eq_set) comp_iso.
unfold comp_iso; do 4 red; intros.
apply H0; apply H; trivial.
Qed.

Lemma comp_iso_eq_fun : A B f f' g g',
  ( x, x A -> f x B) ->
  eq_fun A f f' ->
  eq_fun B g g' ->
  eq_fun A (comp_iso f g) (comp_iso f' g').
unfold comp_iso; red; intros; auto.
Qed.

Lemma comp_iso_typ X Y Z f g :
  typ_fun f X Y ->
  typ_fun g Y Z ->
  typ_fun (comp_iso f g) X Z.
unfold typ_fun, comp_iso; auto.
Qed.

Other properties of isomorphisms


Lemma iso_intro : X Y f g,
  ext_fun X f ->
  ( x, x X -> f x Y /\ g (f x) == x) ->
  ( y y', y Y -> y == y' -> g y == g y' /\ g y X /\ f (g y) == y) ->
  iso_fun X Y f.
intros.
constructor; trivial.
 red; intros.
 apply H0; trivial.

 intros.
 rewrite <- (proj2 (H0 _ H2)); rewrite <- (proj2 (H0 _ H3)).
 apply H1; auto.
 apply H0; trivial.

 intros.
 exists (g y).
  apply H1 with y; auto with *.

  apply H1 with y; auto with *.
Qed.

Lemma iso_fun_inj X1 X2 Y f :
  iso_fun X1 Y f ->
  iso_fun X2 Y f ->
  X1 X2 ->
  X1 == X2.
intros.
apply eq_intro; intros; auto.
assert (tyz1 := iso_typ H0 H2).
assert (tyz2 := iso_inv_typ H tyz1).
assert (eqz1 := iso_inv_eq H tyz1).
apply (iso_inj H0) in eqz1; auto.
rewrite <- eqz1; trivial.
Qed.

Lemma iso_fun_narrow X1 X2 Y1 Y2 f x :
  iso_fun X1 Y1 f ->
  iso_fun X2 Y2 f ->
  X1 X2 ->
  x X2 ->
  f x Y1 ->
  x X1.
intros.
assert (ty1 := iso_inv_typ H H3).
assert (ty2 := iso_typ H ty1).
assert (eq1 := iso_inv_eq H H3).
apply (iso_inj H0) in eq1; trivial.
 rewrite <- eq1; trivial.

 apply H1.
 apply (iso_inv_typ H); trivial.
Qed.

Disjoint sum


Definition sum_isomap f g :=
  sum_case (fun x => inl (f x)) (fun y => inr (g y)).

Lemma sum_isomap_morph : Proper ((eq_set ==> eq_set) ==> (eq_set ==> eq_set) ==> eq_set ==> eq_set) sum_isomap.
unfold sum_isomap; do 4 red; intros.
apply sum_case_morph; trivial.
 red; intros; apply inl_morph; auto.
 red; intros; apply inr_morph; auto.
Qed.

Lemma sum_isomap_ext : A B f f' g g',
  eq_fun A f f' ->
  eq_fun B g g' ->
  eq_fun (sum A B) (sum_isomap f g) (sum_isomap f' g').
unfold sum_isomap; intros.
apply sum_case_ext.
 red; intros; apply inl_morph; auto.
 red; intros; apply inr_morph; auto.
Qed.

Lemma sum_isomap_typ X X' Y Y' f g :
  typ_fun f X X' ->
  typ_fun g Y Y' ->
  typ_fun (sum_isomap f g) (sum X Y) (sum X' Y').
unfold typ_fun, sum_isomap; intros tyf tyg x tyx.
apply sum_ind with (3:=tyx); intros.
 rewrite sum_case_inl0; eauto.
 apply inl_typ.
 apply tyf.
 rewrite H0; rewrite dest_sum_inl; trivial.

 rewrite sum_case_inr0; eauto.
 apply inr_typ.
 apply tyg.
 rewrite H0; rewrite dest_sum_inr; trivial.
Qed.

Lemma sum_iso_fun_morph : X X' Y Y' f g,
  iso_fun X X' f -> iso_fun Y Y' g ->
  iso_fun (sum X Y) (sum X' Y') (sum_isomap f g).
intros.
constructor; intros.
 apply sum_isomap_ext.
  apply (iso_funm H).
  apply (iso_funm H0).

 apply sum_isomap_typ with (1:=iso_typ H) (2:=iso_typ H0); trivial.

 unfold sum_isomap in H3.
 apply sum_ind with (3:=H1); intros;
   apply sum_ind with (3:=H2); intros.
  rewrite sum_case_inl0 in H3; eauto.
  rewrite sum_case_inl0 in H3; eauto.
  apply inl_inj in H3.
  assert (dest_sum x == x0).
   rewrite H5; apply dest_sum_inl.
  assert (dest_sum x' == x1).
   rewrite H7; apply dest_sum_inl.
  apply (iso_inj H) in H3; trivial.
  2:rewrite H8; trivial.
  2:rewrite H9; trivial.
  rewrite H5; rewrite H7; rewrite <- H8; rewrite <- H9; rewrite H3; reflexivity.

  rewrite sum_case_inl0 in H3; eauto.
  rewrite sum_case_inr0 in H3; eauto.
  apply discr_sum in H3; contradiction.

  rewrite sum_case_inr0 in H3; eauto.
  rewrite sum_case_inl0 in H3; eauto.
  symmetry in H3; apply discr_sum in H3; contradiction.

  rewrite sum_case_inr0 in H3; eauto.
  rewrite sum_case_inr0 in H3; eauto.
  apply inr_inj in H3.
  assert (dest_sum x == y).
   rewrite H5; apply dest_sum_inr.
  assert (dest_sum x' == y0).
   rewrite H7; apply dest_sum_inr.
  apply (iso_inj H0) in H3; trivial.
  2:rewrite H8; trivial.
  2:rewrite H9; trivial.
  rewrite H5; rewrite H7; rewrite <- H8; rewrite <- H9; rewrite H3; reflexivity.

 apply sum_ind with (3:=H1); intros.
  destruct (iso_surj H) with (1:=H2).
  exists (inl x0).
   apply inl_typ; trivial.

   unfold sum_isomap.
   rewrite sum_case_inl0; eauto with *.
   2:econstructor;reflexivity.    rewrite H3; apply inl_morph.
   refine (transitivity _ H5); symmetry; apply (iso_funm H); trivial.
   rewrite dest_sum_inl; reflexivity.

  destruct (iso_surj H0) with (1:=H2).
  exists (inr x).
   apply inr_typ; trivial.

   unfold sum_isomap.
   rewrite sum_case_inr0; eauto with *.
   2:econstructor;reflexivity.    rewrite H3; apply inr_morph.
   refine (transitivity _ H5); symmetry; apply (iso_funm H0); trivial.
   rewrite dest_sum_inr; reflexivity.
Qed.

Definition sum_isocomm := sum_case inr inl.

Instance sum_isocomm_morph : morph1 sum_isocomm.
do 2 red; intros; unfold sum_isocomm.
apply sum_case_morph; auto with *.
 apply inr_morph.
 apply inl_morph.
Qed.

Lemma sum_isocomm_typ X Y:
  typ_fun sum_isocomm (sum X Y) (sum Y X).
unfold typ_fun, sum_isocomm; intros.
apply sum_ind with (3:=H); intros.
 rewrite H1; rewrite sum_case_inl; trivial with *.
 apply inr_typ; trivial.

 rewrite H1; rewrite sum_case_inr; trivial with *.
 apply inl_typ; trivial.
Qed.

Lemma sum_isocomm_invol : X Y x,
  x sum X Y -> sum_isocomm (sum_isocomm x) == x.
unfold sum_isocomm; intros.
apply sum_ind with (3:=H); intros.
 rewrite H1; rewrite sum_case_inl; trivial with *.
 rewrite sum_case_inr; auto with *.

 rewrite H1; rewrite sum_case_inr; trivial with *.
 rewrite sum_case_inl; auto with *.
Qed.

Lemma sum_comm_iso_fun :
   X Y, iso_fun (sum X Y) (sum Y X) sum_isocomm.
intros.
apply iso_intro with sum_isocomm; intros; auto with *.
 split.
  apply sum_isocomm_typ; trivial.
  apply sum_isocomm_invol with (1:=H).

 split;[|split].
  apply sum_isocomm_morph; trivial.
  apply sum_isocomm_typ; trivial.
  apply sum_isocomm_invol with (1:=H).
Qed.

Definition sum_isoassoc :=
  sum_case (sum_case inl (fun y => inr (inl y))) (fun z => inr (inr z)).

Instance sum_isoassoc_morph : morph1 sum_isoassoc.
do 2 red; intros; unfold sum_isoassoc.
apply sum_case_morph; trivial.
 red; intros.
 apply sum_case_morph; trivial.
  apply inl_morph.

  red; intros.
  rewrite H1; reflexivity.

 red; intros.
 rewrite H0; reflexivity.
Qed.

Instance inlr_morph : morph1 (fun y => inr (inl y)).
do 2 red; intros.
 rewrite H; reflexivity.
Qed.

Instance inrr_morph : morph1 (fun y => inr (inr y)).
 do 2 red; intros.
 rewrite H; reflexivity.
Qed.

Instance sclr_morph : morph1 (sum_case inl (fun y => inr (inl y))).
do 2 red; intros; apply sum_case_morph; auto with *.
 apply inl_morph.
 apply inlr_morph.
Qed.

Lemma sum_isoassoc_typ : X Y Z,
  typ_fun sum_isoassoc (sum (sum X Y) Z) (sum X (sum Y Z)).
unfold typ_fun, sum_isoassoc; intros.
apply sum_ind with (3:=H); intros.
 rewrite H1; auto with *.
 rewrite sum_case_inl; trivial with *.
 apply sum_ind with (3:=H0); intros.
  rewrite H3; auto with *.
  rewrite sum_case_inl; auto with *.
  apply inl_typ; trivial.

  rewrite H3; auto with *.
  rewrite sum_case_inr; auto with *.
  apply inr_typ; apply inl_typ; trivial.

 rewrite H1; auto with *.
 rewrite sum_case_inr; auto with *.
 apply inr_typ; apply inr_typ; trivial.
Qed.

Lemma sum_assoc_iso_fun :
   X Y Z, iso_fun (sum (sum X Y) Z) (sum X (sum Y Z)) sum_isoassoc.
unfold sum_isoassoc; intros.
constructor; intros.
 apply morph_is_ext.
 apply sum_isoassoc_morph.

 apply sum_isoassoc_typ; trivial.

 apply sum_ind with (3:=H); intros y yty xeq; rewrite xeq in H1|-*;
   [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *;
   (apply sum_ind with (3:=H0); intros y' yty' xeq'; rewrite xeq' in H1|-*;
   [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *).
  apply sum_ind with (3:=yty); intros z zty yeq; rewrite yeq in H1|-*;
    [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *;
    (apply sum_ind with (3:=yty'); intros z' zty' yeq'; rewrite yeq' in H1|-*;
    [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *).
   apply inl_inj in H1; rewrite H1; reflexivity.

   apply discr_sum in H1; contradiction.

   symmetry in H1; apply discr_sum in H1; contradiction.

   apply inr_inj in H1; apply inl_inj in H1; rewrite H1; reflexivity.

  apply sum_ind with (3:=yty); intros z zty yeq; rewrite yeq in H1|-*;
    [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *.
   apply discr_sum in H1; contradiction.

   apply inr_inj in H1; apply discr_sum in H1; contradiction.

  symmetry in H1.
  apply sum_ind with (3:=yty'); intros z' zty' yeq'; rewrite yeq' in H1|-*;
    [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *.
   apply discr_sum in H1; contradiction.

   apply inr_inj in H1; apply discr_sum in H1; contradiction.

  apply inr_inj in H1; apply inr_inj in H1.
  rewrite H1; reflexivity.

 apply sum_ind with (3:=H); intros.
  exists (inl (inl x)).
   apply inl_typ; apply inl_typ; trivial.

   rewrite sum_case_inl; auto with *; rewrite sum_case_inl; auto with *.

  apply sum_ind with (3:=H0); intros.
   exists (inl (inr x)).
    apply inl_typ; apply inr_typ; trivial.

    rewrite sum_case_inl; auto with *; rewrite sum_case_inr; auto with *.
    rewrite H1; rewrite H3; reflexivity.

   exists (inr y1).
    apply inr_typ; trivial.

    rewrite sum_case_inr; auto with *.
    rewrite H1; rewrite H3; reflexivity.
Qed.

Dependent pairs


Definition sigma_isomap f g :=
  fun p => couple (f (fst p)) (g (fst p) (snd p)).

Instance sigma_isomap_morph :
  Proper ((eq_set ==> eq_set) ==> (eq_set ==> eq_set ==> eq_set) ==> eq_set ==> eq_set) sigma_isomap.
unfold sigma_isomap; do 4 red; intros.
apply couple_morph.
 apply fst_morph in H1; auto.

 apply H0.
  apply fst_morph; trivial.
  apply snd_morph; trivial.
Qed.

Lemma sigma_isomap_ext A B f f' g g' :
  ext_fun A B ->
  eq_fun A f f' ->
  ( x x' y y', x A -> x == x' -> y B x -> y == y' -> g x y == g' x' y') ->
  eq_fun (sigma A B) (sigma_isomap f g) (sigma_isomap f' g').
unfold sigma_isomap; red; intros.
apply couple_morph.
 apply fst_typ_sigma in H2; apply fst_morph in H3; auto.

 apply H1.
  apply fst_typ_sigma in H2; trivial.
  apply fst_morph; trivial.
  apply snd_typ_sigma with (2:=H2); auto with *.
  apply snd_morph; trivial.
Qed.

Lemma sigma_isomap_typ A A' B B' f g :
  ext_fun A B ->
  ext_fun A' B' ->
  typ_fun f A A' ->
  ( x, x A -> typ_fun (g x) (B x) (B' (f x))) ->
  typ_fun (sigma_isomap f g) (sigma A B) (sigma A' B').
unfold typ_fun, sigma_isomap; intros eB eB' tyf tyg x tyx.
assert (fst x A).
 apply fst_typ_sigma in tyx; trivial.
apply couple_intro_sigma; auto.
apply tyg; trivial.
apply snd_typ_sigma with (2:=tyx); auto with *.
Qed.

Lemma sigma_iso_fun_morph : A A' B B' f g,
  ext_fun A B ->
  ext_fun A' B' ->
  ext_fun2 A B g ->
  iso_fun A A' f ->
  ( x x', x A -> f x == x' -> iso_fun (B x) (B' x') (g x)) ->
  iso_fun (sigma A B) (sigma A' B') (sigma_isomap f g).
intros.
constructor; intros.
 apply sigma_isomap_ext; intros; auto.
 apply (iso_funm H2).

 apply sigma_isomap_typ; intros; trivial.
  exact (iso_typ H2).
  exact (iso_typ (H3 _ _ H4 (reflexivity _))).

 assert (fst x A).
  apply fst_typ_sigma in H4; trivial.
 apply couple_injection in H6; destruct H6.
 apply (iso_inj H2) in H6.
 2:apply fst_typ_sigma in H4; trivial.
 2:apply fst_typ_sigma in H5; trivial.
 assert (g (fst x) (snd x) == g (fst x) (snd x')).
  rewrite H8; symmetry; apply H1; auto with *.
  apply snd_typ_sigma with (y:=fst x) in H5; auto with *.
 apply (iso_inj (H3 _ _ H7 (reflexivity _))) in H9.
  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H4)).
  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H5)).
  rewrite H6; rewrite H9; reflexivity.

  apply snd_typ_sigma with (2:=H4); auto with *.

  apply snd_typ_sigma with (2:=H5); auto with *.

 destruct (iso_surj H2 (y:=fst y)).
  apply fst_typ_sigma in H4; trivial.
 destruct (iso_surj (H3 _ _ H5 H6) (y:=snd y)).
  apply snd_typ_sigma with (2:=H4); auto with *.
 exists (couple x x0).
  apply couple_intro_sigma; auto.

  refine (transitivity _ _);[|symmetry; apply surj_pair with (1:=subset_elim1 _ _ _ H4)].
  apply couple_morph.
   rewrite <- H6; symmetry; apply (iso_funm H2); trivial.
   symmetry; apply fst_def.

   rewrite <- H8; symmetry; apply H1; trivial.
    symmetry; apply fst_def.
    symmetry; apply snd_def.
Qed.

Lemma sigma_iso_fun_1_l : x F,
  ext_fun (singl x) F ->
  iso_fun (sigma (singl x) F) (F x) snd.
constructor; intros; auto with *.
 red; intros.
 apply snd_typ_sigma with (2:=H0); trivial.
 apply fst_typ_sigma in H0.
 apply singl_elim in H0; auto with *.

 assert (fst x0 == fst x').
  apply fst_typ_sigma in H1.
  apply singl_elim in H1; auto with *.
  rewrite H1.
  apply fst_typ_sigma in H0.
  apply singl_elim in H0; auto with *.
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H0)).
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H1)).
 rewrite H2; rewrite H3; reflexivity.

 exists (couple x y).
  apply couple_intro_sigma; auto.
  apply singl_intro.

  apply snd_def.
Qed.

Lemma sigma_iso_fun_1_l' : x F,
  ext_fun (singl x) F ->
  iso_fun (F x) (sigma (singl x) F) (couple x).
intros.
constructor; intros; auto with *.
 do 2 red; intros; apply couple_morph; auto with *.

 red; intros.
 apply couple_intro_sigma; auto.
 apply singl_intro.

 apply couple_injection in H2; destruct H2; trivial.

 assert (fst y == x).
  apply fst_typ_sigma in H0.
  apply singl_elim in H0; trivial.
 exists (snd y).
  apply eq_elim with (F (fst y)).
   apply H; trivial.
   rewrite H1; apply singl_intro.
  apply snd_typ_sigma with (2:=H0); auto with *.

  rewrite <- H1.
  symmetry; apply surj_pair with (1:=subset_elim1 _ _ _ H0).
Qed.

Lemma sigma_iso_fun_1_r : A B,
  ext_fun A B ->
  ( x, x A -> iso_fun (B x) (singl empty) (fun _ => empty)) ->
  iso_fun (sigma A B) A fst.
intros.
constructor; intros; auto with *.
 red; intros.
 apply fst_typ_sigma in H1; trivial.

 assert ( x y y', x A -> y B x -> y' B x -> y == y').
  intros.
  apply (iso_inj (H0 _ H4)); auto with *.
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H1)).
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H2)).
 apply couple_morph; trivial.
 apply H4 with (fst x); trivial.
  apply fst_typ_sigma in H1; trivial.

  apply snd_typ_sigma with (2:=H1); auto with *.

  apply snd_typ_sigma with (2:=H2); auto with *.

 destruct (iso_surj (H0 _ H1) (y:=empty)).
  apply singl_intro.
 exists (couple y x).
  apply couple_intro_sigma; auto.

  apply fst_def.
Qed.

Definition sigma_1r_iso f x := couple x (f x).

Lemma sigma_1r_iso_typ A B f :
  ext_fun A B ->
  ( x, x A -> f x B x) ->
  typ_fun (sigma_1r_iso f) A (sigma A B).
intros eB tyf x H.
unfold sigma_1r_iso.
apply couple_intro_sigma; auto.
Qed.

Lemma sigma_iso_fun_1_r' : A B f,
  ext_fun A B ->
  ext_fun A f ->
  ( x, x A -> iso_fun (singl empty) (B x) (fun _ => f x)) ->
  iso_fun A (sigma A B) (sigma_1r_iso f).
intros.
unfold sigma_1r_iso.
constructor; intros; auto with *.
 apply sigma_1r_iso_typ; trivial.
 intros.
 apply (iso_typ (H1 _ H2) (singl_intro empty)).

 apply couple_injection in H4; destruct H4; trivial.

 exists (fst y).
  apply fst_typ_sigma in H2; trivial.

 generalize (fst_typ_sigma _ _ _ H2); intros.
 destruct (iso_surj (H1 _ H3)) with (snd y).
  apply snd_typ_sigma with (2:=H2); auto with *.
 rewrite H5.
 symmetry; apply surj_pair with (1:=subset_elim1 _ _ _ H2).
Qed.

Definition sigma_isoassoc :=
  fun t => couple (couple (fst t) (fst (snd t))) (snd (snd t)).

Instance sigma_isoassoc_morph : morph1 sigma_isoassoc.
do 2 red; intros; unfold sigma_isoassoc.
rewrite H; reflexivity.
Qed.

Lemma sigma_isoassoc_typ A B C :
  ext_fun A B ->
  ext_fun2 A B C ->
  typ_fun sigma_isoassoc
    (sigma A (fun x => sigma (B x) (fun y => C x y)))
    (sigma (sigma A B) (fun p => C (fst p) (snd p))).
intros eB eC x tyx.
assert (fst x A).
 apply fst_typ_sigma in tyx; trivial.
assert (snd x sigma (B (fst x)) (fun y => C (fst x) y)).
 apply snd_typ_sigma with (2:=tyx); auto with *.
 do 2 red; intros.
 apply sigma_ext; auto with *.
clear tyx.
assert (fst (snd x) B (fst x)).
 apply fst_typ_sigma in H0; trivial.
assert (snd (snd x) C (fst x) (fst (snd x))).
 apply snd_typ_sigma with (2:=H0); auto with *.
 do 2 red; intros.
 auto with *.
clear H0.
apply couple_intro_sigma; auto with *.
 do 2 red; intros.
 apply eC; auto with *.
  apply fst_typ_sigma in H0; trivial.
  rewrite H3; reflexivity.
  apply snd_typ_sigma with (2:=H0); auto with *.
  rewrite H3; reflexivity.

 apply couple_intro_sigma; auto with *.

 apply eq_elim with (2:=H2).
 apply eC; auto.
  rewrite fst_def; reflexivity.
  rewrite snd_def; reflexivity.
Qed.

Lemma iso_sigma_sigma : A B C,
  ext_fun A B ->
  ext_fun2 A B C ->
  iso_fun (sigma A (fun x => sigma (B x) (fun y => C x y)))
          (sigma (sigma A B) (fun p => C (fst p) (snd p)))
          sigma_isoassoc.
unfold sigma_isoassoc; constructor; intros.
 apply morph_is_ext; apply sigma_isoassoc_morph.

 apply sigma_isoassoc_typ; trivial.

 apply couple_injection in H3; destruct H3.
 apply couple_injection in H3; destruct H3.
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H1)).
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H2)).
 apply couple_morph; trivial.
 assert (snd x sigma (B (fst x)) (fun y => C (fst x) y)).
  apply snd_typ_sigma with (2:=H1); auto with *.
  do 2 red; intros.
  apply sigma_ext; auto with *.
 assert (snd x' sigma (B (fst x)) (fun y => C (fst x) y)).
  apply snd_typ_sigma with (2:=H2); auto with *.
  do 2 red; intros.
  apply sigma_ext; auto with *.
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H6)).
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H7)).
 apply couple_morph; trivial.

 exists (couple (fst (fst y)) (couple (snd (fst y)) (snd y))).
  apply couple_intro_sigma.
   do 2 red; intros.
   apply sigma_ext; auto with *.

   apply fst_typ_sigma in H1.
   apply fst_typ_sigma in H1; trivial.

   apply couple_intro_sigma.
    do 2 red; intros.
    apply H0; auto with *.
    apply fst_typ_sigma in H1.
    apply fst_typ_sigma in H1; trivial.

    apply fst_typ_sigma in H1.
    apply snd_typ_sigma with (2:=H1); auto with *.

    apply snd_typ_sigma with (2:=H1); auto with *.
    do 2 red; intros.
    apply H0; auto with *.
     apply fst_typ_sigma in H2; trivial.
     rewrite H3; reflexivity.
     apply snd_typ_sigma with (2:=H2); auto with *.
     rewrite H3; reflexivity.

  rewrite snd_def.
  rewrite fst_def.
  rewrite fst_def.
  rewrite snd_def.
  specialize fst_typ_sigma with (1:=H1); intros.
  rewrite <- (surj_pair _ _ _ (subset_elim1 _ _ _ H2)).
  rewrite <- (surj_pair _ _ _ (subset_elim1 _ _ _ H1)).
  reflexivity.
Qed.

Definition sum_sigma_iso :=
  sum_case (fun p1 => couple (inl (fst p1)) (snd p1))
           (fun p2 => couple (inr (fst p2)) (snd p2)).

Instance sum_sigma_iso_morph : morph1 sum_sigma_iso.
do 2 red; intros; unfold sum_sigma_iso.
apply sum_case_morph; trivial.
 red; intros.
 rewrite H0; reflexivity.

 red; intros.
 rewrite H0; reflexivity.
Qed.

Instance cpl_inl_morph : morph1 (fun p1 => couple (inl (fst p1)) (snd p1)).
 do 2 red; intros.
 rewrite H; reflexivity.
Qed.
Instance cpl_inr_morph : morph1 (fun p2 => couple (inr (fst p2)) (snd p2)).
 do 2 red; intros.
 rewrite H; reflexivity.
Qed.

Lemma sum_sigma_iso_typ A1 A2 B1 B2 :
  ext_fun A1 B1 ->
  ext_fun A2 B2 ->
  typ_fun sum_sigma_iso
    (sum (sigma A1 B1) (sigma A2 B2))
    (sigma (sum A1 A2) (sum_case B1 B2)).
intros eB1 eB2 x tyx.
unfold sum_sigma_iso.
apply sum_ind with (3:=tyx); intros.
 rewrite sum_case_inl0; eauto.
 rewrite H0; rewrite dest_sum_inl.
 apply couple_intro_sigma; auto.
  apply sum_case_ext; trivial.

  apply inl_typ.
  apply fst_typ_sigma in H; trivial.

  rewrite sum_case_inl0.
   apply snd_typ_sigma with A1; auto.
   apply dest_sum_inl.

   exists (fst x0); auto with *.

 rewrite sum_case_inr0; eauto.
 rewrite H0; rewrite dest_sum_inr.
 apply couple_intro_sigma; auto.
  apply sum_case_ext; trivial.

  apply inr_typ.
  apply fst_typ_sigma in H; trivial.

  rewrite sum_case_inr0.
   apply snd_typ_sigma with A2; auto.
   apply dest_sum_inr.

   exists (fst y); auto with *.
Qed.

Lemma iso_fun_sum_sigma : A1 A2 B1 B2,
  ext_fun A1 B1 ->
  ext_fun A2 B2 ->
  iso_fun (sum (sigma A1 B1) (sigma A2 B2))
          (sigma (sum A1 A2) (sum_case B1 B2))
          sum_sigma_iso.
unfold sum_sigma_iso; intros A1 A2 B1 B2 bm1 bm2.
constructor; intros.
 apply sum_case_ext; apply morph_is_ext; auto with *.

 apply sum_sigma_iso_typ; trivial.

 apply sum_ind with (3:=H); intros y yty xeq; rewrite xeq in H1|-*;
   [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *;
   (apply sum_ind with (3:=H0); intros y' yty' xeq'; rewrite xeq' in H1|-*;
   [rewrite sum_case_inl in H1|rewrite sum_case_inr in H1]; trivial with *);
   apply couple_injection in H1; destruct H1.
  apply inl_inj in H1.
  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ yty)).
  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ yty')).
  rewrite H1; rewrite H2; reflexivity.

  apply discr_sum in H1; contradiction.

  symmetry in H1; apply discr_sum in H1; contradiction.

  apply inr_inj in H1.
  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ yty)).
  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ yty')).
  rewrite H1; rewrite H2; reflexivity.

 assert (m4 : morph1 (fun x => inl (couple x (snd y)))).
  do 2 red; intros.
  rewrite H0; reflexivity.
 assert (m4' : morph1 (fun x => inr (couple x (snd y)))).
  do 2 red; intros.
  rewrite H0; reflexivity.
 exists (sum_case (fun x => inl (couple x (snd y))) (fun x => inr (couple x (snd y))) (fst y)).
  apply sum_ind with (3:=fst_typ_sigma _ _ _ H); intros.
   rewrite H1; trivial.
   rewrite sum_case_inl; trivial.
   apply inl_typ.
   apply couple_intro_sigma; auto with *.
   apply snd_typ_sigma with (y:=fst y) in H; auto with *.
   2:apply sum_case_ext; trivial.
   rewrite sum_case_inl0 in H; eauto.
   revert H; apply eq_elim; apply bm1;
     rewrite H1; rewrite dest_sum_inl; auto with *.

   rewrite H1; trivial.
   rewrite sum_case_inr; trivial.
   apply inr_typ.
   apply couple_intro_sigma; auto with *.
   apply snd_typ_sigma with (y:=fst y) in H; auto with *.
   2:apply sum_case_ext; trivial.
   rewrite sum_case_inr0 in H; eauto.
   revert H; apply eq_elim; apply bm2;
     rewrite H1; rewrite dest_sum_inr; auto with *.

  apply sum_ind with (3:=fst_typ_sigma _ _ _ H); intros.
   rewrite H1; trivial.
   rewrite sum_case_inl; trivial.
   rewrite sum_case_inl; trivial with *.
   rewrite fst_def; rewrite snd_def.
   rewrite <- H1.
   rewrite <- surj_pair with (1:=subset_elim1 _ _ _ H); auto with *.

   rewrite H1; trivial.
   rewrite sum_case_inr; trivial.
   rewrite sum_case_inr; trivial with *.
   rewrite fst_def; rewrite snd_def.
   rewrite <- H1.
   rewrite <- surj_pair with (1:=subset_elim1 _ _ _ H); auto with *.
Qed.

Cartesian product


Lemma prodcart_iso_fun_morph : X X' Y Y' f g,
  iso_fun X X' f -> iso_fun Y Y' g ->
  iso_fun (prodcart X Y) (prodcart X' Y') (sigma_isomap f (fun _ => g)).
intros.
cut (iso_fun (sigma X (fun _ => Y)) (sigma X' (fun _ => Y'))
       (sigma_isomap f (fun _ => g))).
 apply iso_fun_morph.
  symmetry; apply sigma_nodep.

  symmetry; apply sigma_nodep.

  red; intros.
  unfold sigma_isomap.
  apply couple_morph.
   apply (iso_funm H).
    apply fst_typ_sigma in H1; trivial.
    apply fst_morph; trivial.

   apply (iso_funm H0).
    apply snd_typ_sigma with (2:=H1) (y:=fst x); auto with *.
    apply snd_morph; trivial.
apply sigma_iso_fun_morph; auto.
red; intros.
apply (iso_funm H0); trivial.
Qed.

Lemma sigma_isomap_typ_prod A A' B B' f g :
  typ_fun f A A' ->
  typ_fun g B B' ->
  typ_fun (sigma_isomap f (fun _ => g)) (prodcart A B) (prodcart A' B').
red; intros.
rewrite sigma_nodep in H1|-*.
revert H1; apply sigma_isomap_typ; trivial.
Qed.

Lemma prodcart_comm_iso_fun :
   X Y, iso_fun (prodcart X Y) (prodcart Y X) (fun p => couple (snd p) (fst p)).
constructor; intros.
 do 2 red; intros.
 rewrite H0; reflexivity.

 red; intros.
 apply couple_intro.
  apply snd_typ in H; trivial.
  apply fst_typ in H; trivial.

 apply couple_injection in H1; destruct H1.
 rewrite (surj_pair _ _ _ H).
 rewrite (surj_pair _ _ _ H0).
 apply couple_morph; trivial.

 exists (couple (snd y) (fst y)).
  apply couple_intro.
   apply snd_typ in H; trivial.
   apply fst_typ in H; trivial.

  rewrite fst_def; rewrite snd_def.
  symmetry; apply surj_pair with (1:=H).
Qed.


Definition prodcart_sigma_iso q :=
  couple (couple (fst (fst q)) (fst (snd q)))
         (couple (snd (fst q)) (snd (snd q))).

Lemma prodcart_sigma_iso_typ A1 A2 B1 B2 :
  ext_fun A1 B1 ->
  ext_fun A2 B2 ->
  typ_fun prodcart_sigma_iso
    (prodcart (sigma A1 B1) (sigma A2 B2))
    (sigma (prodcart A1 A2) (fun p => prodcart (B1 (fst p)) (B2 (snd p)))).
intros eB1 eB2 x H.
assert (ef : ext_fun (prodcart A1 A2)
     (fun p => prodcart (B1 (fst p)) (B2 (snd p)))).
 do 2 red; intros.
 apply prodcart_morph.
  apply eB1.
   apply fst_typ in H0; trivial.
   apply fst_morph; trivial.
  apply eB2.
   apply snd_typ in H0; trivial.
   apply snd_morph; trivial.
generalize (fst_typ _ _ _ H); intro.
generalize (snd_typ _ _ _ H); intro.
clear H.
apply couple_intro_sigma; trivial.
 apply couple_intro.
  apply fst_typ_sigma in H0; trivial.
  apply fst_typ_sigma in H1; trivial.

 apply couple_intro.
  apply snd_typ_sigma with (2:=H0); auto with *.
  rewrite fst_def; reflexivity.

  apply snd_typ_sigma with (2:=H1); auto with *.
  rewrite snd_def; reflexivity.
Qed.

Lemma iso_fun_prodcart_sigma : A1 A2 B1 B2,
  ext_fun A1 B1 ->
  ext_fun A2 B2 ->
  iso_fun (prodcart (sigma A1 B1) (sigma A2 B2))
    (sigma (prodcart A1 A2) (fun p => prodcart (B1 (fst p)) (B2 (snd p))))
    prodcart_sigma_iso.
unfold prodcart_sigma_iso; intros.
assert (ef : ext_fun (prodcart A1 A2)
     (fun p => prodcart (B1 (fst p)) (B2 (snd p)))).
 do 2 red; intros.
 apply prodcart_morph.
  apply H.
   apply fst_typ in H1; trivial.
   apply fst_morph; trivial.
  apply H0.
   apply snd_typ in H1; trivial.
   apply snd_morph; trivial.
constructor; intros.
 do 2 red; intros.
 rewrite H2; reflexivity.

 apply prodcart_sigma_iso_typ; trivial.

 apply couple_injection in H3; destruct H3.
 apply couple_injection in H3; destruct H3.
 apply couple_injection in H4; destruct H4.
 rewrite surj_pair with (1:=H1);
 rewrite surj_pair with (1:=H2).
 rewrite surj_pair with (1:=subset_elim1 _ _ _ (fst_typ _ _ _ H1)).
 rewrite surj_pair with (1:=subset_elim1 _ _ _ (snd_typ _ _ _ H1)).
 rewrite surj_pair with (1:=subset_elim1 _ _ _ (fst_typ _ _ _ H2)).
 rewrite surj_pair with (1:=subset_elim1 _ _ _ (snd_typ _ _ _ H2)).
 apply couple_morph; apply couple_morph; trivial.

 exists (couple (couple (fst (fst y)) (fst (snd y))) (couple (snd (fst y)) (snd (snd y)))).
  generalize (fst_typ_sigma _ _ _ H1); intros.
  apply snd_typ_sigma with (y:=fst y) in H1; auto with *.
   apply couple_intro.
    apply couple_intro_sigma; auto with *.
     apply fst_typ in H2; trivial.
     apply fst_typ in H1; trivial.

    apply couple_intro_sigma; auto with *.
     apply snd_typ in H2; trivial.
     apply snd_typ in H1; trivial.

  repeat (rewrite fst_def || rewrite snd_def).
  assert (H2:=H1).
  generalize (fst_typ_sigma _ _ _ H1); intros.
  apply snd_typ_sigma with (y:=fst y) in H2; auto with *.
  rewrite <- surj_pair with (1:=H3).
  rewrite <- surj_pair with (1:=H2).
  rewrite <- surj_pair with (1:=subset_elim1 _ _ _ H1); reflexivity.
Qed.

Dependent product


Definition cc_prod_isomap A' f g :=
  fun fct => cc_lam A' (fun x' => g (f x') (cc_app fct (f x'))).

Instance cc_prod_isomap_morph :
  Proper (eq_set ==> (eq_set ==> eq_set) ==> (eq_set ==> eq_set ==> eq_set) ==> eq_set ==> eq_set) cc_prod_isomap.
unfold cc_prod_isomap; do 5 red; intros.
apply cc_lam_morph; trivial.
red; intros; apply H1; auto.
apply cc_app_morph; auto.
Qed.

Lemma cc_prod_isomap_ext A B A' A'' f f' g g' :
  A' == A'' ->
  ext_fun A B ->
  eq_fun A' f f' ->
  typ_fun f A' A ->
  ( x x' y y', x A' -> x == x' -> y B (f x) -> y == y' ->
   g (f x) y == g' (f' x') y') ->
  eq_fun (cc_prod A B) (cc_prod_isomap A' f g) (cc_prod_isomap A'' f' g').
unfold cc_prod_isomap; red; intros.
apply cc_lam_ext; trivial.
red; intros.
apply H3; trivial.
 apply cc_prod_elim with (1:=H4); auto.
 apply cc_app_morph; auto with *.
Qed.

Lemma cc_prod_isomap_typ A A' B B' f g :
  ext_fun A' B' ->
  ext_fun A' f ->
  ext_fun2 A B g ->
  typ_fun f A' A ->
  ( x, x A' -> typ_fun (g (f x)) (B (f x)) (B' x)) ->
  typ_fun (cc_prod_isomap A' f g) (cc_prod A B) (cc_prod A' B').
intros eB' fm gm tyf tyg x H.
unfold cc_prod_isomap.
apply cc_prod_intro; trivial; intros.
 do 2 red; intros.
 apply gm; auto with *.
  apply cc_prod_elim with (1:=H); auto.

  apply cc_app_morph; auto with *.

 apply tyg; trivial.
 apply cc_prod_elim with (1:=H); auto.
Qed.

Lemma cc_prod_iso_fun_morph : A A' B B' f g,
  ext_fun A B ->
  ext_fun A' B' ->
  ext_fun2 A B g ->
  iso_fun A' A f ->
  ( x, x A' -> iso_fun (B (f x)) (B' x) (g (f x))) ->
  iso_fun (cc_prod A B) (cc_prod A' B') (cc_prod_isomap A' f g).
intros.
assert (fm := iso_funm H2).
assert (tyf := iso_typ H2).
assert (gext : h h' x x',
  x A' ->
  x == x' ->
  h cc_prod A B ->
  h == h' ->
  g (f x) (cc_app h (f x)) ==
  g (f x') (cc_app h' (f x'))).
 intros.
 apply H1; auto.
  apply cc_prod_elim with (1:=H6); auto.
  apply cc_app_morph; auto.
unfold cc_prod_isomap; constructor; intros.
 apply cc_prod_isomap_ext; intros; auto with *.

 apply cc_prod_isomap_typ; intros; trivial.
 exact (iso_typ (H3 _ H4)).

 rewrite (cc_eta_eq _ _ _ H4).
 rewrite (cc_eta_eq _ _ _ H5).
 apply cc_lam_ext; intros; auto with *.
 red; intros.
 destruct (iso_surj H2) with x0; trivial.
 generalize (cc_app_morph _ _ H6 _ _ (reflexivity x1)).
 rewrite cc_beta_eq; trivial.
  rewrite cc_beta_eq; trivial.
   intro.
   rewrite <- H8; rewrite <- H10.
   apply (iso_inj (H3 _ H9)) in H11; trivial.
    apply cc_prod_elim with (1:=H4); trivial.
    rewrite <- H10 in H7; trivial.

    apply cc_prod_elim with (1:=H5); trivial.
    rewrite <- H10 in H7; trivial.

   do 2 red; intros.
   apply gext; auto with *.

  do 2 red; intros.
  apply gext; auto with *.

 assert (f'm : ext_fun A (fun x => let x' := iso_inv A' f x in
                                   iso_inv (B (f x')) (g (f x')) (cc_app y x'))).
  do 2 red; intros.
  apply iso_inv_ext; auto.
   apply H.
    apply tyf.
    apply iso_inv_typ with (1:=H2); trivial.

    apply fm.
     apply iso_inv_typ with (1:=H2); trivial.
     apply iso_inv_morph0; trivial.

   red; intros.
   apply H1; auto with *.
    apply tyf.
    apply iso_inv_typ with (1:=H2); trivial.

    apply fm.
     apply iso_inv_typ with (1:=H2); trivial.
     apply iso_inv_morph0; trivial.

   apply cc_app_morph; auto with *.
   apply iso_inv_morph0; trivial.
 exists (cc_lam A (fun x => let x' := iso_inv A' f x in
                            iso_inv (B (f x')) (g (f x')) (cc_app y x'))).
  apply cc_prod_intro; intros; auto.
  assert (iso_inv A' f x A').
   apply iso_inv_typ with (1:=H2); trivial.
  assert (f (iso_inv A' f x) == x).
   apply iso_inv_eq with (1:=H2); trivial.
  apply eq_elim with (B (f (iso_inv A' f x))).
   symmetry; apply H; auto with *.
  apply iso_inv_typ with (1:=H3 _ H6).
  apply cc_prod_elim with (1:=H4); trivial.

  rewrite (cc_eta_eq _ _ _ H4).
  apply cc_lam_ext; intros; auto with *.
  red; intros.
  assert (x == iso_inv A' f (f x)).
   symmetry.
   apply iso_inv_eq2 with (1:=H2); auto.
  transitivity (g (f x) (iso_inv (B (f x)) (g (f x)) (cc_app y x))).
   symmetry; apply H1; auto with *.
    apply iso_inv_typ with (1:=H3 _ H5).
    apply cc_prod_elim with (1:=H4); trivial.

    rewrite cc_beta_eq; auto.
     apply iso_inv_ext; auto with *.
      red; intros.
      apply H1; auto.

      apply cc_app_morph; auto with *.

   rewrite iso_inv_eq with (1:=H3 _ H5).
    apply cc_app_morph; auto with *.
    apply cc_prod_elim with (1:=H4); trivial.
Qed.

Lemma cc_prod_iso_fun_0_l : a F,
  iso_fun (cc_prod empty F) (singl a) (fun _ => a).
intros.
constructor; intros; auto with *.
 red; intros.
 apply singl_intro.

 rewrite (cc_eta_eq _ _ _ H).
 rewrite (cc_eta_eq _ _ _ H0).
 apply cc_lam_ext; auto with *.
 red; intros.
 apply empty_ax in H2; contradiction.

 exists (cc_lam empty (fun _ => empty)).
  apply cc_prod_intro; intros; auto with *.
   do 2 red; intros.
   apply empty_ax in H0; contradiction.

   apply empty_ax in H0; contradiction.

  apply singl_elim in H; auto with *.
Qed.

Lemma cc_prod_iso_fun_0_l' : a F,
  iso_fun (singl a) (cc_prod empty F) (fun _ => cc_lam empty (fun _ => empty)).
constructor; intros.
 do 2 red; intros.
 apply cc_lam_ext; auto with *.
 red; intros.
 apply empty_ax in H1; contradiction.

 red; intros.
 apply cc_prod_intro; intros; auto with *.
  do 2 red; intros.
  apply empty_ax in H0; contradiction.

  apply empty_ax in H0; contradiction.

 apply singl_elim in H; apply singl_elim in H0; rewrite H0; trivial.

 exists a.
  apply singl_intro.

  refine (transitivity _ (symmetry (cc_eta_eq _ _ _ H))).
  apply cc_lam_ext; auto with *.
  red; intros.
  apply empty_ax in H0; contradiction.
Qed.

Definition cc_prod_iso1l x := fun f => cc_app f x.

Lemma cc_prod_iso_fun_1_l : x F,
  ( x', x == x' -> F x == F x') ->
  iso_fun (cc_prod (singl x) F) (F x) (cc_prod_iso1l x).
unfold cc_prod_iso1l; constructor; intros.
 do 2 red; intros.
 rewrite H1; reflexivity.

 red; intros.
 apply cc_prod_elim with (1:=H0).
 apply singl_intro.

 rewrite (cc_eta_eq _ _ _ H0).
 rewrite (cc_eta_eq _ _ _ H1).
 apply cc_lam_ext; auto with *.
 red; intros.
 rewrite <- H4.
 apply singl_elim in H3; rewrite H3; trivial.

 exists (cc_lam (singl x) (fun _ => y)).
  apply cc_prod_intro; intros.
   do 2 red; reflexivity.

   do 2 red; intros.
   apply singl_elim in H1.
   transitivity (F x).
    symmetry; auto with *.
    apply H; rewrite <- H1; trivial.

   apply singl_elim in H1.
   symmetry in H1.
   rewrite <- H with (1:=H1); trivial.

  rewrite cc_beta_eq; auto with *.
  apply singl_intro.
Qed.

Lemma cc_prod_iso_fun_1_l' : x F,
  ( x', x == x' -> F x == F x') ->
  iso_fun (F x) (cc_prod (singl x) F) (fun y => cc_lam (singl x) (fun _ => y)).
constructor; intros.
 do 2 red; intros.
 apply cc_lam_ext; intros; auto with *.
 red; trivial.

 red; intros.
 apply cc_prod_intro; intros.
  do 2 red; reflexivity.

  do 2 red; intros.
  apply singl_elim in H1.
  rewrite H1 in H2; symmetry in H1.
  transitivity (F x);[symmetry|]; auto.

  revert H0; apply eq_elim.
  apply singl_elim in H1; symmetry in H1; auto.

 generalize (cc_app_morph _ _ H2 _ _ (reflexivity x)).
 rewrite cc_beta_eq; auto with *.
 2:apply singl_intro.
 rewrite cc_beta_eq; auto with *.
 apply singl_intro.

 exists (cc_app y x).
  apply cc_prod_elim with (1:=H0).
  apply singl_intro.

  refine (transitivity _ (symmetry (cc_eta_eq _ _ _ H0))).
  apply cc_lam_ext; auto with *.
  red; intros.
  apply singl_elim in H1.
  rewrite H1 in H2; apply cc_app_morph;auto with *.
Qed.

Lemma cc_prod_iso_fun_1_r : A F,
  ext_fun A F ->
  ( x, x A -> iso_fun (F x) (singl empty) (fun _ => empty)) ->
  iso_fun (cc_prod A F) (singl empty) (fun _ => empty).
constructor; intros.
 do 2 red; reflexivity.

 red; intros.
 apply singl_intro.

 rewrite (cc_eta_eq _ _ _ H1).
 rewrite (cc_eta_eq _ _ _ H2).
 apply cc_lam_ext; intros; auto with *.
 red; intros.
 rewrite <- H5.
 apply (iso_inj (H0 _ H4)); auto with *.
  apply cc_prod_elim with (1:=H1); trivial.
  apply cc_prod_elim with (1:=H2); trivial.

 exists (cc_lam A (fun x => iso_inv (F x) (fun _ => empty) empty)).
  apply cc_prod_intro; intros; trivial.
   do 2 red; intros.
   unfold iso_inv.
   apply union_morph; apply subset_morph; auto with *.

   apply iso_inv_typ with (1:=H0 _ H2).
   apply singl_intro.

  apply singl_elim in H1; auto with *.
Qed.

Definition cc_prod_isocurry A B :=
  fun f2 => cc_lam (sigma A B) (fun p => cc_app (cc_app f2 (fst p)) (snd p)).

Lemma cc_prod_isocurry_typ A B C :
  ext_fun A B ->
  ext_fun2 A B C ->
  typ_fun (cc_prod_isocurry A B)
    (cc_prod A (fun x => cc_prod (B x) (fun y => C x y)))
    (cc_prod (sigma A B) (fun p => C (fst p) (snd p))).
intros eB eC x H.
unfold cc_prod_isocurry.
apply cc_prod_intro; intros.
 do 2 red; intros.
 rewrite H1; reflexivity.

 do 2 red; intros.
 apply eC.
  apply fst_typ_sigma in H0; trivial.
  rewrite H1; reflexivity.
  apply snd_typ_sigma with (2:=H0); auto with *.
  rewrite H1; reflexivity.

 apply cc_prod_elim with (dom := B (fst x0)) (F:=fun y => C (fst x0) y).
  apply cc_prod_elim with (1:=H).
  apply fst_typ_sigma in H0; trivial.

  apply snd_typ_sigma with (2:=H0); auto with *.
Qed.

Lemma cc_prod_curry_iso_fun : A B C,
  ext_fun A B ->
  ext_fun2 A B C ->
  iso_fun (cc_prod A (fun x => cc_prod (B x) (fun y => C x y)))
    (cc_prod (sigma A B) (fun p => C (fst p) (snd p)))
    (cc_prod_isocurry A B).
unfold cc_prod_isocurry; constructor; intros.
 do 2 red; intros.
 apply cc_lam_ext; intros; auto with *.
 red; intros.
 rewrite H2; rewrite H4; reflexivity.

 apply cc_prod_isocurry_typ; trivial.

 rewrite (cc_eta_eq _ _ _ H1).
 rewrite (cc_eta_eq _ _ _ H2).
 apply cc_lam_ext; intros; auto with *.
 red; intros.
 rewrite <- H5.
  clear x'0 H5.
 rewrite (cc_eta_eq _ _ _ (cc_prod_elim _ _ _ _ H1 H4)).
 rewrite (cc_eta_eq _ _ _ (cc_prod_elim _ _ _ _ H2 H4)).
 apply cc_lam_ext; intros; auto with *.
 red; intros.
 rewrite <- H6.
 clear x'0 H6.
 assert (couple x0 x1 sigma A B).
  apply couple_intro_sigma; trivial.
 generalize (cc_app_morph _ _ H3 _ _ (reflexivity (couple x0 x1))).
 rewrite cc_beta_eq; trivial.
 2:do 2 red; intros; rewrite H8; reflexivity.
 rewrite cc_beta_eq; trivial.
 2:do 2 red; intros; rewrite H8; reflexivity.
 rewrite fst_def; rewrite snd_def; trivial.

 exists (cc_lam A (fun x => cc_lam (B x) (fun y' => cc_app y (couple x y')))).
  apply cc_prod_intro; intros; auto with *.
   do 2 red; intros.
   apply cc_lam_ext; intros; auto with *.
   red; intros.
   rewrite H3; rewrite H5; reflexivity.

   do 2 red; intros.
   apply cc_prod_ext; intros; auto with *.
   red; intros; auto.

   apply cc_prod_intro; intros; auto with *.
    do 2 red; intros.
    rewrite H4; reflexivity.

    do 2 red; intros; auto with *.

    assert (couple x x0 sigma A B).
     apply couple_intro_sigma; auto with *.
    specialize cc_prod_elim with (1:=H1) (2:=H4); intro.
    apply eq_elim with (2:=H5).
    symmetry; apply H0; auto with *.
     rewrite fst_def; reflexivity.
     rewrite snd_def; reflexivity.

  transitivity (cc_lam (sigma A B) (fun p => cc_app y p)).
  2:symmetry; apply cc_eta_eq with (1:=H1).
  apply cc_lam_ext; intros; auto with *.
  red; intros.
  rewrite <- H3; clear x' H3.
  rewrite cc_beta_eq.
  3:apply fst_typ_sigma in H2; trivial.
   rewrite cc_beta_eq.
    rewrite <- (surj_pair _ _ _ (subset_elim1 _ _ _ H2)); auto with *.

    do 2 red; intros.
    rewrite H4; reflexivity.

    apply snd_typ_sigma with (2:=H2); auto with *.

   do 2 red; intros.
   apply cc_lam_ext; auto with *.
   red; intros.
   rewrite H4; rewrite H6; reflexivity.
Qed.

Definition cc_prod_sigma_iso A :=
  fun fct => couple (cc_lam A (fun x => fst (cc_app fct x)))
                    (cc_lam A (fun x => snd (cc_app fct x))).

Lemma cc_prod_sigma_iso_typ A B C :
  ext_fun A B ->
  ext_fun2 A B C ->
  typ_fun (cc_prod_sigma_iso A)
    (cc_prod A (fun x => sigma (B x) (fun y => C x y)))
    (sigma (cc_prod A B) (fun f => cc_prod A (fun x => C x (cc_app f x)))).
intros eB eC x H.
unfold cc_prod_sigma_iso.
apply couple_intro_sigma.
 do 2 red; intros.
 apply cc_prod_ext; intros; auto with *.
 red; intros.
 apply eC; auto with *.
  apply cc_prod_elim with (1:=H0); trivial.
  rewrite H3; rewrite H1; reflexivity.

 apply cc_prod_intro; intros; auto with *.
  do 2 red; intros.
  rewrite H1; reflexivity.

  specialize cc_prod_elim with (1:=H) (2:=H0); intro.
  apply fst_typ_sigma in H1; trivial.

 apply cc_prod_intro; intros.
  do 2 red; intros.
  rewrite H1; reflexivity.

  do 2 red; intros.
  apply eC; trivial.
   rewrite cc_beta_eq; auto with *.
    specialize cc_prod_elim with (1:=H) (2:=H0); intros.
    apply fst_typ_sigma in H2; trivial.

    do 2 red; intros.
    rewrite H3; reflexivity.

   apply cc_app_morph; trivial.
   apply cc_lam_ext; intros; auto with *.
   red; intros.
   rewrite H3 ;reflexivity.

  specialize cc_prod_elim with (1:=H) (2:=H0); intro.
  apply snd_typ_sigma with (2:=H1); auto with *.
   do 2 red; intros; apply eC; auto with *.

   rewrite cc_beta_eq; auto with *.
   do 2 red; intros.
   rewrite H3; reflexivity.
Qed.

Instance cc_prod_sigma_iso_morph : morph2 cc_prod_sigma_iso.
do 3 red; intros.
unfold cc_prod_sigma_iso.
apply couple_morph.
 apply cc_lam_ext; trivial.
 red; intros.
 rewrite H0; rewrite H2; reflexivity.

 apply cc_lam_ext; trivial.
 red; intros.
 rewrite H0; rewrite H2; reflexivity.
Qed.

Lemma iso_fun_cc_prod_sigma : A B C,
  ext_fun A B ->
  ext_fun2 A B C ->
  iso_fun (cc_prod A (fun x => sigma (B x) (fun y => C x y)))
    (sigma (cc_prod A B) (fun f => cc_prod A (fun x => C x (cc_app f x))))
    (cc_prod_sigma_iso A).
intros A B C Bm Cm.
unfold cc_prod_sigma_iso; constructor; intros.
 apply morph_is_ext; apply cc_prod_sigma_iso_morph; reflexivity.

 apply cc_prod_sigma_iso_typ; trivial.

 apply couple_injection in H1; destruct H1.
 rewrite (cc_eta_eq _ _ _ H).
 rewrite (cc_eta_eq _ _ _ H0).
 apply cc_lam_ext; intros; auto with *.
 red; intros.
 rewrite <- H4 in H4|-*; clear x'0.
 generalize (cc_app_morph _ _ H1 _ _ H4);
 generalize (cc_app_morph _ _ H2 _ _ H4).
 repeat rewrite cc_beta_eq; auto; try (do 2 red; intros; rewrite H6; reflexivity).
 intros.
 specialize cc_prod_elim with (1:=H) (2:=H3); intro.
 specialize cc_prod_elim with (1:=H0) (2:=H3); intro.
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H7)).
 rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H8)).
 rewrite H5; rewrite H6; reflexivity.

 exists (cc_lam A (fun x => couple (cc_app (fst y) x) (cc_app (snd y) x))).
  apply cc_prod_intro; intros.
   do 2 red; intros.
   rewrite H1; reflexivity.

   do 2 red; intros.
   apply sigma_ext; intros; auto with *.

   apply couple_intro_sigma.
    do 2 red; intros; apply Cm; auto with *.

    apply fst_typ_sigma in H.
    apply cc_prod_elim with (1:=H); trivial.

    apply snd_typ_sigma with (y:= fst y) in H; auto with *.
     apply cc_prod_elim with (1:=H); trivial.

     do 2 red; intros.
     apply cc_prod_ext; auto with *.
     red; intros.
     apply Cm; auto.
      apply cc_prod_elim with (1:=H1); trivial.
      rewrite H2; rewrite H4; reflexivity.

  rewrite (surj_pair _ _ _ (subset_elim1 _ _ _ H)).
  apply couple_morph.
   apply fst_typ_sigma in H.
   rewrite (cc_eta_eq _ _ _ H).
   apply cc_lam_ext; intros; auto with *.
   red; intros.
   rewrite <- H1.
   clear H1 x'.
   rewrite cc_beta_eq; trivial.
    apply fst_def.

    do 2 red; intros.
    rewrite H2; reflexivity.

   apply snd_typ_sigma with (y:=fst y) in H; auto with *.
    rewrite (cc_eta_eq _ _ _ H).
    apply cc_lam_ext; intros; auto with *.
    red; intros.
    rewrite <- H1.
    clear H1 x'.
    rewrite cc_beta_eq; trivial.
     apply snd_def.

     do 2 red; intros.
     rewrite H2; reflexivity.

    do 2 red; intros.
    apply cc_prod_ext; intros; auto with *.
    red; intros.
    apply Cm; trivial.
     apply cc_prod_elim with (1:=H0); trivial.
     rewrite H1; rewrite H3; reflexivity.
Qed.

Definition prodcart_cc_prod_iso D :=
  fun p => cc_lam D (sum_case (cc_app (fst p)) (cc_app (snd p))).

Instance prodcart_cc_prod_iso_morph : morph2 prodcart_cc_prod_iso.
do 3 red; intros.
unfold prodcart_cc_prod_iso.
apply cc_lam_ext; intros; auto with *.
red; intros.
apply sum_case_morph; trivial.
 red; intros.
 rewrite H0; rewrite H3; reflexivity.

 red; intros.
 rewrite H0; rewrite H3; reflexivity.
Qed.

Lemma prodcart_cc_prod_iso_typ A1 A2 F1 F2 :
  ext_fun A1 F1 ->
  ext_fun A2 F2 ->
  typ_fun (prodcart_cc_prod_iso (sum A1 A2))
    (prodcart (cc_prod A1 F1) (cc_prod A2 F2))
    (cc_prod (sum A1 A2) (sum_case F1 F2)).
intros eF1 eF2 x H.
unfold prodcart_cc_prod_iso.
apply cc_prod_intro; intros.
 do 2 red; intros.
 apply sum_case_morph; auto with *.
  apply cc_app_morph; reflexivity.
  apply cc_app_morph; reflexivity.

 do 2 red; intros.
 apply sum_case_ext with (A1:=A1) (A2:=A2); trivial.

 apply sum_ind with (3:=H0); intros.
  rewrite sum_case_inl0; eauto.
  rewrite sum_case_inl0; eauto.
  apply fst_typ in H.
  apply cc_prod_elim with (1:=H); trivial.
  rewrite H2; rewrite dest_sum_inl; trivial.

  rewrite sum_case_inr0; eauto.
  rewrite sum_case_inr0; eauto.
  apply snd_typ in H.
  apply cc_prod_elim with (1:=H); trivial.
  rewrite H2; rewrite dest_sum_inr; trivial.
Qed.

Lemma iso_fun_prodcart_cc_prod : A1 A2 F1 F2,
  ext_fun A1 F1 ->
  ext_fun A2 F2 ->
  iso_fun (prodcart (cc_prod A1 F1) (cc_prod A2 F2))
    (cc_prod (sum A1 A2) (sum_case F1 F2))
    (prodcart_cc_prod_iso (sum A1 A2)).
constructor; intros.
 apply morph_is_ext; apply prodcart_cc_prod_iso_morph; reflexivity.

 apply prodcart_cc_prod_iso_typ; trivial.

 unfold prodcart_cc_prod_iso in H3.
 rewrite surj_pair with (1:=H1).
 rewrite surj_pair with (1:=H2).
 apply couple_morph.
  apply fst_typ in H1.
  apply fst_typ in H2.
  rewrite cc_eta_eq with (1:=H1).
  rewrite cc_eta_eq with (1:=H2).
  apply cc_lam_ext; intros; auto with *.
  red; intros.
  rewrite <- H5; clear H5 x'0.
  generalize (cc_app_morph _ _ H3 _ _ (reflexivity (inl x0))).
  rewrite cc_beta_eq.
   3:apply inl_typ; trivial.
   rewrite sum_case_inl.
   2:apply cc_app_morph; reflexivity.
   rewrite cc_beta_eq.
    3:apply inl_typ; trivial.
    rewrite sum_case_inl; trivial.
    apply cc_app_morph; reflexivity.

    do 2 red; intros.
    apply sum_case_morph; trivial.
     apply cc_app_morph; reflexivity.
     apply cc_app_morph; reflexivity.

   do 2 red; intros.
   apply sum_case_morph; trivial.
    apply cc_app_morph; reflexivity.
    apply cc_app_morph; reflexivity.

  apply snd_typ in H1.
  apply snd_typ in H2.
  rewrite cc_eta_eq with (1:=H1).
  rewrite cc_eta_eq with (1:=H2).
  apply cc_lam_ext; intros; auto with *.
  red; intros.
  rewrite <- H5; clear H5 x'0.
  generalize (cc_app_morph _ _ H3 _ _ (reflexivity (inr x0))).
  rewrite cc_beta_eq.
   3:apply inr_typ; trivial.
   rewrite sum_case_inr.
   2:apply cc_app_morph; reflexivity.
   rewrite cc_beta_eq.
    3:apply inr_typ; trivial.
    rewrite sum_case_inr; trivial.
    apply cc_app_morph; reflexivity.

    do 2 red; intros.
    apply sum_case_morph; trivial.
     apply cc_app_morph; reflexivity.
     apply cc_app_morph; reflexivity.

   do 2 red; intros.
   apply sum_case_morph; trivial.
    apply cc_app_morph; reflexivity.
    apply cc_app_morph; reflexivity.

 exists (couple (cc_lam A1 (fun a => cc_app y (inl a))) (cc_lam A2 (fun b => cc_app y (inr b)))).
  apply couple_intro.
   apply cc_prod_intro; intros; auto with *.
    do 2 red; intros.
    rewrite H3; reflexivity.

    setoid_replace (F1 x) with (sum_case F1 F2 (inl x)).
     apply cc_prod_elim with (1:=H1).
     apply inl_typ; trivial.

     rewrite sum_case_inl0.
     2:exists x; reflexivity.
     apply H; trivial.
     rewrite dest_sum_inl; reflexivity.

   apply cc_prod_intro; intros; auto with *.
    do 2 red; intros.
    rewrite H3; reflexivity.

    setoid_replace (F2 x) with (sum_case F1 F2 (inr x)).
     apply cc_prod_elim with (1:=H1).
     apply inr_typ; trivial.

     rewrite sum_case_inr0.
     2:exists x; reflexivity.
     apply H0; trivial.
     rewrite dest_sum_inr; reflexivity.

  unfold prodcart_cc_prod_iso.
  transitivity (cc_lam (sum A1 A2) (fun a => cc_app y a)).
  2:symmetry; apply cc_eta_eq with (1:=H1).
  apply cc_lam_ext; intros; auto with *.
  red; intros.
  rewrite <- H3; clear H3 x'.
  apply sum_ind with (3:=H2); intros.
   rewrite sum_case_inl0; eauto with *.
   rewrite fst_def.
   rewrite H4; rewrite dest_sum_inl.
   rewrite cc_beta_eq; auto with *.
   do 2 red; intros.
   rewrite H6; reflexivity.

   rewrite sum_case_inr0; eauto with *.
   rewrite snd_def.
   rewrite H4; rewrite dest_sum_inr.
   rewrite cc_beta_eq; auto with *.
   do 2 red; intros.
   rewrite H6; reflexivity.
Qed.

Transfinite iteration


Section TI_iso.

  Definition TI_iso F g o :=
    cc_app (REC (fun o f => cc_lam (F (TI F o)) (g (cc_app f))) o).

Lemma iso_cont : F G o f,
  Proper (incl_set ==> incl_set) F ->
  Proper (incl_set ==> incl_set) G ->
  isOrd o ->
  ( o', o' o -> iso_fun (TI F (osucc o')) (TI G (osucc o')) f) ->
  iso_fun (TI F o) (TI G o) f.
intros F G o f Fmono Gmono oo iso'.
assert (Fm := Fmono_morph _ Fmono).
assert (Gm := Fmono_morph _ Gmono).
constructor; intros.
 do 2 red; intros.
 apply TI_elim in H; trivial.
 destruct H.
 apply (iso_funm (iso' _ H)); trivial.
 rewrite TI_mono_succ; trivial.
 apply isOrd_inv with o; trivial.

 red; intros.
 apply TI_elim in H; trivial.
 destruct H.
 apply TI_intro with x0; trivial.
 rewrite <- TI_mono_succ; eauto using isOrd_inv.
 apply (iso_typ (iso' _ H)).
 rewrite TI_mono_succ; eauto using isOrd_inv.

 apply TI_elim in H; trivial.
 destruct H.
 apply TI_elim in H0; trivial.
 destruct H0.
 red in H,H0.
 assert (exists2 z, z o & x F (TI F z) /\ x' F (TI F z)).
  destruct (isOrd_dir _ oo x0 x1); trivial.
  destruct H5.
  exists x2; trivial.
  split.
   revert H2; apply Fmono.
   apply TI_mono; eauto using isOrd_inv.

   revert H3; apply Fmono.
   apply TI_mono; eauto using isOrd_inv.
 destruct H4.
 destruct H5.
 apply (iso_inj (iso' _ H4)); trivial.
  rewrite TI_mono_succ; eauto using isOrd_inv.
  rewrite TI_mono_succ; eauto using isOrd_inv.

 apply TI_elim in H; auto.
 destruct H.
 destruct (iso_surj (iso' _ H)) with y.
  rewrite TI_mono_succ; eauto using isOrd_inv.
 exists x0; trivial.
 apply TI_intro with x; trivial.
 rewrite <- TI_mono_succ; eauto using isOrd_inv.
Qed.

  Variable F G : set -> set.
  Variable g : (set -> set) -> set -> set.
  Variable o : set.
  Hypothesis Fmono : Proper (incl_set ==> incl_set) F.
  Hypothesis Gmono : Proper (incl_set ==> incl_set) G.
  Hypothesis gext : X f f', eq_fun X f f' -> eq_fun (F X) (g f) (g f').
  Hypothesis isog' : o f, isOrd o ->
    iso_fun (TI F o) (TI G o) f -> iso_fun (F (TI F o)) (G (TI G o)) (g f).
  Hypothesis oord : isOrd o.

  Let Fm := Fmono_morph _ Fmono.
  Let Gm := Fmono_morph _ Gmono.
  Let egf : o' f, isOrd o' -> ext_fun (F (TI F o')) (g (cc_app f)).
do 2 red; intros.
apply (@gext (TI F o')); trivial.
red; intros; apply cc_app_morph; auto with *.
Qed.

  Lemma TI_iso_recursor :
    recursor o (TI F)
      (fun o f => iso_fun (TI F o) (TI G o) (cc_app f))
      (fun o f => cc_lam (F (TI F o)) (g (cc_app f))).
constructor; intros.
 apply TI_morph.

 rewrite TI_eq; auto.
 apply sup_morph; auto with *.
 red; intros.
 rewrite TI_mono_succ; auto with *.
  apply Fm.
  apply TI_morph; trivial.

  rewrite <- H1; apply isOrd_inv with o0; trivial.

 revert H3; apply iso_fun_morph; auto with *.
  apply TI_morph; trivial.
  apply TI_morph; trivial.
  red; intros.
  rewrite <- H4; auto.

  apply iso_cont; trivial.

 do 3 red; intros.
 apply cc_lam_ext.
  apply Fm; apply TI_morph; auto.

  red; intros.
  apply (@gext (TI F x)); trivial.
   red; intros; apply cc_app_morph; auto with *.

 split.
  rewrite TI_mono_succ; auto with *.
  apply is_cc_fun_lam; auto.

  apply isog' in H2; trivial.
  revert H2; apply iso_fun_morph.
   symmetry; apply TI_mono_succ; eauto using isOrd_inv.
   symmetry; apply TI_mono_succ; eauto using isOrd_inv.

   red; intros.
   rewrite cc_beta_eq; auto.
    apply (@gext (TI F o0)); trivial.
    red; intros.
    rewrite H5; reflexivity.

    rewrite <- H3; trivial.

 red; intros.
 red; intros.
 destruct H1 as (oo0,(ofun,oiso)); destruct H2 as (oo',(o'fun,o'iso)).
 rewrite cc_beta_eq; auto.
 2:rewrite TI_mono_succ in H4; auto with *.
 rewrite cc_beta_eq; auto.
  apply (@gext (TI F o0)); auto with *.
   red; intros.
   rewrite <- H2; auto.

   rewrite <- TI_mono_succ; auto.

  rewrite TI_mono_succ in H4; auto with *.
  revert H4; apply Fmono; apply TI_mono; auto.
Qed.

  Lemma TI_iso_fun :
    iso_fun (TI F o) (TI G o) (TI_iso F g o) /\
    ( x, x TI F o -> TI_iso F g o x == g (TI_iso F g o) x).
split; intros.
 apply REC_typing with (1:=oord) (2:=TI_iso_recursor).

 unfold TI_iso.
 rewrite REC_expand with (1:=oord) (2:=TI_iso_recursor); trivial.
 rewrite cc_beta_eq; auto with *.
 rewrite <- TI_mono_succ; auto.
 revert H; apply TI_incl; auto.
Qed.

  Lemma TI_iso_irrel o' o'' :
    isOrd o' ->
    isOrd o'' ->
    o' o'' ->
    o'' o ->
    eq_fun (TI F o') (TI_iso F g o') (TI_iso F g o'').
red; intros.
unfold TI_iso at 2; rewrite <- H4.
apply REC_ord_irrel with (2:=TI_iso_recursor); auto with *.
Qed.

  Lemma TI_iso_fixpoint :
    TI F o == F (TI F o) <-> TI G o == G (TI G o).
assert (iso1 := proj1 TI_iso_fun).
assert (iso2 := isog' oord iso1).
assert (same_iso : eq_fun (TI F o) (TI_iso F g o) (g (TI_iso F g o))).
 red; intros.
 transitivity (TI_iso F g o x').
  unfold TI_iso; rewrite H0; auto with *.
 rewrite H0 in H.
 apply TI_iso_fun; trivial.
assert (iso1' : iso_fun (TI F o) (TI G o) (g (TI_iso F g o))).
 revert iso1; apply iso_fun_morph; auto with *.
clear iso1.
split; intros.
 apply iso_fun_sym in iso1'.
 apply iso_fun_inj with (TI F o) (iso_inv (TI F o) (g (TI_iso F g o))); trivial.
  apply iso_fun_sym.
  generalize iso2; apply iso_fun_morph; auto with *.
  apply iso_funm in iso2; trivial.

  rewrite <- TI_mono_succ; auto.
  apply TI_incl; auto.

 apply iso_fun_inj with (TI G o) (g (TI_iso F g o)); trivial.
  apply iso_change_rhs with (G (TI G o)); auto with *.

  rewrite <- TI_mono_succ; auto.
  apply TI_incl; auto.
Qed.

End TI_iso.

Section TIF_iso.

  Variable A : set.
  Variable F G : (set -> set) -> set -> set.
  Hypothesis Fm : Proper ((eq_set==>eq_set)==>eq_set==>eq_set) F.
  Hypothesis Gm : Proper ((eq_set==>eq_set)==>eq_set==>eq_set) G.
  Hypothesis Fmono : mono_fam A F.
  Hypothesis Gmono : mono_fam A G.

Lemma TIF_iso_cont : o f,
  isOrd o ->
  ( a o', a A -> o' o ->
   iso_fun (TIF A F (osucc o') a) (TIF A G (osucc o') a) (f a)) ->
   a, a A -> iso_fun (TIF A F o a) (TIF A G o a) (f a).
intros o f oo iso' a tya.
constructor; intros.
 do 2 red; intros.
 apply TIF_elim in H; trivial.
 destruct H.
 apply (iso_funm (iso' _ _ tya H)); trivial.
 rewrite TIF_mono_succ; trivial.
 apply isOrd_inv with o; trivial.

 red; intros.
 apply TIF_elim in H; trivial.
 destruct H.
 apply TIF_intro with x0; trivial.
 rewrite <- TIF_mono_succ; eauto using isOrd_inv.
 apply (iso_typ (iso' _ _ tya H)).
 rewrite TIF_mono_succ; eauto using isOrd_inv.

 apply TIF_elim in H; trivial.
 destruct H.
 apply TIF_elim in H0; trivial.
 destruct H0.
 red in H,H0.
 assert (exists2 z, z o & x F (TIF A F z) a /\ x' F (TIF A F z) a).
  destruct (isOrd_dir _ oo x0 x1); trivial.
  destruct H5.
  exists x2; trivial.
  split.
   revert H2; apply Fmono; auto with *.
    apply TIF_morph; reflexivity.
    apply TIF_morph; reflexivity.
   red; intros.
   transitivity (TIF A F x2 a0).
    apply TIF_mono; eauto using isOrd_inv.

    red; intro; apply eq_elim.
    apply TIF_morph; auto with *.

   revert H3; apply Fmono; auto with *.
    apply TIF_morph; reflexivity.
    apply TIF_morph; reflexivity.
   red; intros.
   transitivity (TIF A F x2 a0).
    apply TIF_mono; eauto using isOrd_inv.

    red; intro; apply eq_elim.
    apply TIF_morph; auto with *.
 destruct H4.
 destruct H5.
 apply (iso_inj (iso' _ _ tya H4)); trivial.
  rewrite TIF_mono_succ; eauto using isOrd_inv.
  rewrite TIF_mono_succ; eauto using isOrd_inv.

 apply TIF_elim in H; auto.
 destruct H.
 destruct (iso_surj (iso' _ _ tya H)) with y.
  rewrite TIF_mono_succ; eauto using isOrd_inv.
 exists x0; trivial.
 apply TIF_intro with x; trivial.
 rewrite <- TIF_mono_succ; eauto using isOrd_inv.
Qed.

  Let fmrph g f o :
    isOrd o ->
    Proper ((eq_set==>eq_set==>eq_set)==>eq_set==>eq_set==>eq_set) g ->
    ext_fun (sigma A (fun a' => TIF A F (osucc o) a'))
     (fun p => g (fun x y => cc_app f (couple x y)) (fst p) (snd p)).
do 2 red; intros.
apply H0.
2:apply fst_morph; trivial.
2:apply snd_morph; trivial.
do 2 red; intros.
rewrite H3; rewrite H4; reflexivity.
Qed.

  Definition TIF_iso g o a x :=
    cc_app (REC (fun o f =>
         cc_lam (sigma A (fun a' => TIF A F (osucc o) a'))
              (fun p => g (fun x y => cc_app f (couple x y)) (fst p) (snd p))) o)
      (couple a x).

  Variable g : (set -> set -> set) -> set -> set -> set.
  Hypothesis gm : Proper ((eq_set==>eq_set==>eq_set)==>eq_set==>eq_set==>eq_set) g.
  Hypothesis gext :
      X f f', morph1 X -> morph2 f -> morph2 f' ->
     ( a, a A -> eq_fun (X a) (f a) (f' a)) ->
      a, a A -> eq_fun (F X a) (g f a) (g f' a).
  Hypothesis isog :
      X Y f, morph1 X -> morph1 Y -> morph2 f ->
     ( a, a A -> iso_fun (X a) (Y a) (f a)) ->
       a, a A -> iso_fun (F X a) (G Y a) (g f a).

  Variable o : set.
  Variable oo : isOrd o.

  Lemma TIF_iso_recursor :
    recursor o (fun o => sigma A (fun a' => TIF A F o a'))
      (fun o f => a, a A -> iso_fun (TIF A F o a) (TIF A G o a) (fun x => cc_app f (couple a x)))
      (fun o f => cc_lam (sigma A (fun a' => TIF A F (osucc o) a'))
            (fun p => g (fun x y => cc_app f (couple x y)) (fst p) (snd p))).
constructor; intros.
 do 2 red; intros; apply sigma_morph; auto with *.
 red; intros; apply TIF_morph; auto with *.

 rewrite <- sigma_cont.
 2:do 3 red; intros; apply TIF_morph; auto with *.
 2:apply osucc_morph; trivial.
 apply sigma_ext; intros; auto with *.
 rewrite TIF_eq; auto with *.
 apply sup_morph; intros; auto with *.
 red; intros.
 rewrite <- TIF_mono_succ; eauto using isOrd_inv.
 apply TIF_morph; trivial.
 apply osucc_morph; trivial.

 generalize (H3 _ H4); apply iso_fun_morph; auto with *.
  apply TIF_morph; auto with *.
  apply TIF_morph; auto with *.

  red; intros.
  rewrite <- H6; apply H2.
  apply couple_intro_sigma; trivial.
  do 2 red; intros; apply TIF_morph; auto with *.

 apply TIF_iso_cont with (f:=fun a0 x => cc_app f (couple a0 x)); auto.

 do 3 red; intros.
 apply cc_lam_morph; intros.
  apply sigma_morph; auto with *.
  red; intros; apply TIF_morph; trivial.
  apply osucc_morph; trivial.

  red; intros.
  apply gm.
   do 2 red; intros.
   rewrite H0; rewrite H2; rewrite H3; reflexivity.

   apply fst_morph; trivial.

   apply snd_morph; trivial.

 split.
  apply is_cc_fun_lam; auto.

  intros.
  apply isog with (a:=a) in H2; trivial.
  2:apply TIF_morph; auto with *.
  2:apply TIF_morph; auto with *.
   revert H2; apply iso_fun_morph.
    symmetry; apply TIF_mono_succ; eauto using isOrd_inv.
    symmetry; apply TIF_mono_succ; eauto using isOrd_inv.

    red; intros.
    rewrite cc_beta_eq; auto.
     apply gm.
      do 2 red; intros; apply cc_app_morph; auto with *.
      apply couple_morph; trivial.

      symmetry; apply fst_def.

      rewrite snd_def; auto with *.

    apply couple_intro_sigma; trivial.
     do 2 red; intros; apply TIF_morph; auto with *.

     rewrite <- H4.
     rewrite TIF_mono_succ; auto.

   do 3 red; intros.
   rewrite H4; rewrite H5; reflexivity.

 red; intros.
 red; intros.
 destruct H1 as (oo0,(ofun,oiso)); destruct H2 as (oo',(o'fun,o'iso)).
 rewrite cc_beta_eq; auto.
 assert (tyfx := fst_typ_sigma _ _ _ H4).
 rewrite cc_beta_eq; auto.
  red in gext.
  apply gext with (X:=TIF A F o0); auto with *.
   apply TIF_morph; auto with *.
   do 3 red; intros; apply cc_app_morph; auto with *.
   apply couple_morph; trivial.
   do 3 red; intros; apply cc_app_morph; auto with *.
   apply couple_morph; trivial.

   red; intros.
   rewrite <- H5; apply H3.
   apply couple_intro_sigma; trivial.
   do 2 red; intros; apply TIF_morph; auto with *.

   apply snd_typ_sigma with (y:=fst x) in H4; auto with *.
   2:do 2 red; intros; apply TIF_morph; auto with *.
   revert H4; apply eq_elim.
   apply TIF_mono_succ; auto with *.

  revert H4; apply sigma_mono; auto with *.
   do 2 red; intros; apply TIF_morph; auto with *.

   do 2 red; intros; apply TIF_morph; auto with *.

   intros.
   transitivity (TIF A F (osucc o') x0).
    apply TIF_mono; auto with *.
    red; intros.
    apply ole_lts; eauto using isOrd_inv.
    apply olts_le in H4; transitivity o0; trivial.

    red; intro; apply eq_elim.
    apply TIF_morph; auto with *.
Qed.

  Lemma TIF_iso_fun :
     a, a A ->
    iso_fun (TIF A F o a) (TIF A G o a) (TIF_iso g o a) /\
    ( x, x TIF A F o a -> TIF_iso g o a x == g (TIF_iso g o) a x).
intros a tya.
split; intros.
 unfold TIF_iso.
 revert a tya.
 apply REC_typing with (1:=oo) (2:=TIF_iso_recursor).

 assert (couple a x sigma A (fun a' => TIF A F o a')).
  apply couple_intro_sigma; trivial.
  do 2 red; intros; apply TIF_morph; auto with *.
 unfold TIF_iso; rewrite REC_expand with (1:=oo) (2:=TIF_iso_recursor); trivial.
 rewrite cc_beta_eq; auto with *.
  apply gm.
   do 2 red; intros.
   apply cc_app_morph; auto with *.
   apply couple_morph; trivial.

   apply fst_def.

   apply snd_def.

 revert H0; apply sigma_mono; auto with *.
  do 2 red; intros; apply TIF_morph; auto with *.
  do 2 red; intros; apply TIF_morph; auto with *.

  intros.
  transitivity (TIF A F (osucc o) x0).
   apply TIF_mono; auto.
   red; intros; apply isOrd_trans with o; auto.

   red; intro; apply eq_elim.
   apply TIF_morph; auto with *.
Qed.

End TIF_iso.