Library sset10

Theory of Sets EIII-6 Infinite sets

Copyright INRIA (2009-2011) Apics Team (Jose Grimm).

Require Import ssreflect ssrbool eqtype ssrnat ssrfun.
Set Implicit Arguments.
Unset Strict Implicit.
Import Prenex Implicits.
Require Export sset9.


Module InfiniteSets.

EIII-6-1 The set of natural integers


Lemma infinite_Bnat: infinite_set Bnat.
Proof. by case (finite_dichot1 Bnat) => // fs; elim Bnat_infinite. Qed.

EIII-6-2 Definition of mappings by induction


Definition induction_defined s a:= choose(fun f=>
  source f = Bnat & surjection f & W 0c f = a &
  forall n, inc n Bnat -> W (succ n) f = s (W n f)).

Definition induction_defined1 h a p := choose(fun f=>
  source f = Bnat & surjection f & W 0c f = a &
  (forall n, n <c p -> W (succ n) f = h n (W n f)) &
  (forall n, inc n Bnat -> ~ (n <=c p) -> W n f = a)).

Definition induction_defined_set s a E:= choose(fun f=>
  is_function f &source f = Bnat & target f = E & W 0c f = a &
  forall n, inc n Bnat -> W (succ n) f = s (W n f)).

Definition induction_defined0_set h a E:= choose(fun f=>
  is_function f & source f = Bnat & target f = E & W 0c f = a &
  forall n, inc n Bnat -> W (succ n) f = h n (W n f)).

Definition induction_defined1_set h a p E := choose(fun f=>
  is_function f &source f = Bnat & target f = E & W 0c f = a &
  (forall n, cardinal_lt n p -> W (succ n) f = h n (W n f)) &
  (forall n, inc n Bnat -> ~ (cardinal_le n p) -> W n f = a)).

Lemma integer_induction1: forall h a p, inc p Bnat ->
  exists_unique (fun f=> source f = Bnat & surjection f &
    W 0c f = a &
     (forall n, cardinal_lt n p -> W (succ n) f = h n (W n f))&
     (forall n, inc n Bnat -> ~ (cardinal_le n p) -> W n f = a)).
Proof.
move=> h a p pB; split.
set (h1:= fun n x => Yo (cardinal_lt n p) (h n x) a).
move: (integer_induction0 h1 a) => [[f [sf [sjf [f0 fn]]]] _].
exists f; ee.
    move => n np; rewrite fn; [rewrite /h1 Y_if_rw // | Bnat_tac].
  move => n nB np.
  have nnz: (n <> 0c) by dneg nz; rewrite nz; fprops.
  move: (predc_pr nB nnz) => [pnB nsp].
  by rewrite nsp (fn _ pnB) /h1 Y_if_not_rw // - lt_n_succ_le//- nsp.
move=> x y [sx [sjx [x0 [xs xl]]]][sy [sjy [y0 [ys yl]]]].
apply function_exten4=>//; first by ue.
rewrite sx; apply cardinal_c_induction; first by ue.
move=> n nB eq.
case (p_or_not_p (n <c p)) => np.
  by rewrite (xs _ np) (ys _ np) eq.
have snp: (~ (succ n) <=c p) by srw; fprops.
move: (BS_succ nB) => snB.
by rewrite (xl _ snB snp) (yl _ snB snp).
Qed.

Lemma induction_defined_pr: forall s a,
  let f := induction_defined s a in
     source f = Bnat & surjection f & W 0c f = a &
     forall n, inc n Bnat -> W (succ n) f = s (W n f).
Proof.
move=> s a f.
rewrite /f/induction_defined.
move: (integer_induction s a)=> [e _].
apply choose_pr=> //.
Qed.

Lemma induction_defined_pr1: forall h a p,
  let f := induction_defined1 h a p in
    inc p Bnat ->
    ( source f = Bnat & surjection f &
      W 0c f = a &
      (forall n, n <c p -> W (succ n) f = h n (W n f))&
      (forall n, inc n Bnat -> ~ (n <=c p) -> W n f = a)).
Proof.
move=> h a p f pB.
rewrite /f/induction_defined1.
move: (integer_induction1 h a pB)=> [e _].
apply choose_pr=> //.
Qed.

Lemma integer_induction_stable: forall E g a,
  inc a E -> (forall x, inc x E -> inc (g x) E) ->
  sub (target (induction_defined g a)) E.
Proof.
move=> E g a eA agE.
move:(induction_defined_pr g a) => [sf [sjf [f0 fn]]] t tt.
move:(surjective_pr2 sjf tt) => [x [xsf]] <-; rewrite sf in xsf.
move: x xsf;apply cardinal_c_induction; first by ue.
by move=> n nB WE; rewrite fn //; apply agE.
Qed.

Lemma integer_induction_stable0: forall E h a,
  inc a E -> (forall n x, inc x E -> inc n Bnat -> inc (h n x) E) ->
  sub (target (induction_defined0 h a)) E.
Proof.
move=> E h a aE ahE.
move:(induction_defined_pr0 h a) => [sf [sjf [f0 fn]]] t tt.
move:(surjective_pr2 sjf tt) => [x [xsf]] <-; rewrite sf in xsf.
move: x xsf;apply cardinal_c_induction; first by ue.
by move=> n nB WE; rewrite fn //; apply ahE.
Qed.

Lemma integer_induction_stable1: forall E h a p,
  inc p Bnat ->
  inc a E -> (forall n x, inc x E -> cardinal_lt n p -> inc (h n x) E) ->
  sub (target (induction_defined1 h a p)) E.
Proof.
move=> E h a p pB aE ahE.
move:(induction_defined_pr1 h a pB) => [sf [sjf [f0 [fs lf]]]] t tt.
move:(surjective_pr2 sjf tt) => [x [xsf]] <-; rewrite sf in xsf.
move: x xsf;apply cardinal_c_induction; first by ue.
move=> n nB WE.
case (p_or_not_p (n <c p)) => np.
  rewrite fs //; apply ahE =>//.
have nsp: ~ cardinal_le (succ n) p by srw; fprops.
rewrite lf //; hprops.
Qed.

Lemma induction_defined_pr_set: forall E g a,
  let f := induction_defined_set g a E in
    inc a E -> (forall x, inc x E -> inc (g x) E) ->
     (is_function f & source f = Bnat & target f = E & W 0c f = a &
     forall n, inc n Bnat -> W (succ n) f = g (W n f)).
Proof.
move=> E g a f aE ag.
rewrite /f/induction_defined_set; apply choose_pr.
move: (induction_defined_pr g a) => [sf [[fjf sjf] [f0 fn]]].
set (h:= corresp Bnat E (graph (induction_defined g a))).
have fh:(is_function h).
  rewrite /h; apply is_function_pr; [fprops | idtac | aw;ue].
  apply sub_trans with (target (induction_defined g a)).
    apply f_range_graph =>//.
  apply integer_induction_stable =>//.
exists h.
rewrite /h/W; rewrite corresp_source corresp_target corresp_graph ; ee.
Qed.

Lemma induction_defined_pr_set0: forall E h a,
  let f := induction_defined0_set h a E in
    inc a E -> (forall n x, inc x E -> inc n Bnat -> inc (h n x) E) ->
     (is_function f & source f = Bnat & target f = E & W 0c f = a &
     forall n, inc n Bnat -> W (succ n) f = h n (W n f)).
Proof.
move=> E g a f aE ag.
rewrite /f/induction_defined0_set; apply choose_pr.
move: (induction_defined_pr0 g a) => [sf [[fjf sjf] [f0 fn]]].
set (h:= corresp Bnat E (graph (induction_defined0 g a))).
have fh:(is_function h).
  rewrite /h; apply is_function_pr; [fprops | idtac | aw;ue].
  apply sub_trans with (target (induction_defined0 g a)).
    apply f_range_graph =>//.
  apply integer_induction_stable0 =>//.
exists h;rewrite /h/W corresp_source corresp_target corresp_graph ; ee.
Qed.

Lemma induction_defined_pr_set1: forall E h a p,
  let f := induction_defined1_set h a p E in
    inc p Bnat ->
    inc a E -> (forall n x, inc x E -> n <c p -> inc (h n x) E) ->
    (is_function f & source f = Bnat & target f = E & W 0c f = a &
      (forall n, n <c p -> W (succ n) f = h n (W n f))&
      (forall n, inc n Bnat -> ~ (n <=c p) -> W n f = a)).
Proof.
move=> E g a p f pB aE ag.
rewrite /f/induction_defined1_set; apply choose_pr.
move: (induction_defined_pr1 g a pB) => [sf [[fjf sjf] [f0 [fs fl]]]].
set (h:= corresp Bnat E (graph (induction_defined1 g a p))).
have fh:(is_function h).
  rewrite /h; apply is_function_pr; [fprops | idtac | aw;ue].
  apply sub_trans with (target (induction_defined1 g a p)).
    apply f_range_graph =>//.
  apply integer_induction_stable1 =>//.
exists h;rewrite /h/W corresp_source corresp_target corresp_graph ; ee.
Qed.

EIII-6-3 Properties of infinite cardinals


Lemma infinite_greater_countable1: forall E,
  infinite_set E -> (cardinal Bnat) <=c (cardinal E).
Proof.
move=> E iE; red;ee.
rewrite /Bnat (cardinal_of_cardinal omega0_cardinal) -omega0_pr1 //.
apply cardinal_ordinal; fprops.
Qed.

Lemma infinite_greater_countable: forall E,
  infinite_set E -> exists F, sub F E & cardinal F = cardinal Bnat.
Proof.
move=> E ise.
move: (infinite_greater_countable1 ise).
rewrite - cardinal_le_aux2; fprops.
rewrite - eq_subset_card; move=> [F [fe ef]]; exists F;ee; symmetry; aw.
Qed.

Lemma equipotent_N2_N: (product Bnat Bnat) \Eq Bnat.
Proof.
set g2 := fun a => (binom (succ a) 2c).
set mi:= fun n m => n +c (g2 (n +c m)).
have g2B: forall a, inc a Bnat -> inc (g2 a) Bnat.
   rewrite /g2=> a aB; apply BS_binom =>//; hprops.
have miB: forall n m, inc n Bnat -> inc m Bnat -> inc (mi n m) Bnat.
  by move=> n m nB mB; rewrite /mi; hprops.
have ha: forall n m, inc n Bnat -> inc m Bnat ->
    (g2 (n +c m)) <=c (mi n m).
  move=> n m nB mB; rewrite /mi.
  set t:= (g2 (n +c m)).
  rewrite card_plusC; apply (Bsum_increasing3 (g2B _ (BS_plus nB mB)) nB).
have hc: forall n, inc n Bnat-> g2 (succ n) = (g2 n) +c (succ n).
  by move=> n nB; rewrite /g2 (binom_2plus0 (BS_succ nB)).
have hb: forall n m, inc n Bnat -> inc m Bnat ->
  (mi n m) <c (g2 (succ (n +c m))).
  move=> n m nB mB.
  move: (BS_plus nB mB) => sB.
  rewrite (hc _ sB) /mi.
  set t:= (g2 (card_plus n m)).
  have aux: inc t Bnat by rewrite /t; apply g2B; fprops.
  rewrite card_plusC; apply (finite_sum2_lt aux nB aux (BS_succ sB)); fprops.
  srw; apply Bsum_increasing3; fprops.
exists (BL (fun z => (mi (P z) (Q z))) (product Bnat Bnat) Bnat).
rewrite bl_source bl_target; ee;apply bl_bijective.
  move => t; rewrite product_inc_rw; move=> [_ [pB qB]]; intuition.
  move=> u v;rewrite !product_inc_rw; move=> [pu [puB quB]][pv [pvB qvB]] sm.
  have ss: card_plus (P u) (Q u) = card_plus (P v) (Q v).
    move: (ha _ _ puB quB)(hb _ _ puB quB)(ha _ _ pvB qvB)(hb _ _ pvB qvB).
    rewrite sm; move=> r1 r2 r3 r4.
    move: (cardinal_le_lt_trans r1 r4)(cardinal_le_lt_trans r3 r2)=> r5 r6.
    have gi: forall x y, inc x Bnat -> inc y Bnat ->
      (g2 x) <c (g2 (succ y)) -> x <=c y.
      have ls2: forall z, inc z Bnat -> 2c <=c (succ (succ z)).
        move => z zB; rewrite -succ_one -(lt_n_succ_le1 cardinal1 (BS_succ zB)).
        rewrite -succ_zero; rewrite -(lt_n_succ_le1 cardinal0 zB); fprops.
      have n2z: 2c <> 0c by apply card_two_not_zero.
      move=> x y xB yB; rewrite /g2.
      rewrite - (binom_monotone2 inc2_Bnat (BS_succ xB) (BS_succ (BS_succ yB)) n2z).
      rewrite (lt_is_le_succ _ (BS_succ yB)) - lt_n_succ_le1; fprops.
      fprops.
    move : (BS_succ yB)=> h;fprops.
    move: (BS_plus puB quB) (BS_plus pvB qvB) => sun svn.
    apply (cardinal_antisymmetry1 (gi _ _ sun svn r5)(gi _ _ svn sun r6)).
  move: sm; rewrite /mi ss; set (w:= g2 (card_plus (P v) (Q v))).
  have wB: inc w Bnat by apply (g2B _ (BS_plus pvB qvB)).
  move=> ss2; move: (plus_simplifiable_right wB puB pvB ss2) => sp.
  rewrite sp in ss; apply (pair_exten pu pv sp).
  apply (plus_simplifiable_left pvB quB qvB ss).
move=> y yB.
have g2z: g2 0c = 0c.
  rewrite /g2 succ_zero (binom_bad inc1_Bnat inc2_Bnat) //.
  rewrite -succ_one; apply (is_lt_succ inc1_Bnat).
  fprops.
case (equal_or_not y 0c) => yz.
  rewrite yz; exists (J 0c 0c).
  move: inc0_Bnat => bz.
  split; [fprops | rewrite pr1_pair pr2_pair].
  by rewrite /mi (Bnat0_unit_suml bz) g2z (Bnat0_unit_suml bz).
set (p:= fun k=> inc k Bnat & cardinal_lt y (g2 k)).
have pa: forall k, p k -> inc k Bnat by move=> k [kB _].
have pb: (~ p 0c).
  rewrite /p g2z; move=> [_ aux]; apply (zero_smallest1 aux).
have pc: exists k, p k.
  exists (succ y); rewrite /p; ee.
  move: (is_lt_succ yB) => ysy.
  rewrite /g2 binom_2plus0; last by hprops.
  move: (BS_succ yB) => syB.
  have ax: (succ y) <=c (binom (succ y) 2c +c (succ y)).
    rewrite card_plusC; apply (Bsum_increasing3 syB(BS_binom syB inc2_Bnat)).
    move: (g2B _ yB)=> gB; fprops.
  co_tac.
move:(least_int_prop1 pa pb pc) => [x [xB [psx npx]]].
move: (hc _ xB) => bp.
have p1: y <=c ((g2 x) +c x).
  move: psx => [_];rewrite bp.
  rewrite (plus_via_succ _ xB).
  rewrite (lt_is_le_succ _ (BS_plus (g2B _ xB) xB)) //.
have p2: cardinal_le (g2 x) y.
  have cg2: is_cardinal (g2 x) by move: (g2B _ xB); fprops.
  have cy: is_cardinal y by fprops.
  case (cardinal_le_total_order2 cg2 cy) => h; first by exact h.
   elim npx;red; split; assumption.
move: (g2B _ xB) => g2Bx.
move: (card_sub_pr p2); set n:= (y -c (g2 x)).
move=> p3;rewrite -p3 in p1.
have nB:inc n Bnat by apply BS_sub.
move: (plus_le_simplifiable g2Bx nB xB p1) => lenx.
move: (card_sub_pr lenx); set m:= (x -c n).
move=> p4;rewrite -p4 in p3.
have mB: inc m Bnat by rewrite /m; apply BS_sub.
exists (J n m); split; first by apply product_pair_inc; exact.
by rewrite /mi pr1_pair pr2_pair card_plusC p3.
Qed.

Theorem equipotent_inf2_inf: forall a, infinite_c a ->
  a ^c 2c = a.
Proof.
move=> E ciE.
have cE:is_cardinal E by move: ciE => [ok _].
have cEE:cardinal E = E by apply cardinal_of_cardinal.
have isE:infinite_set E by red; rewrite cEE; red in ciE; intuition.
set (base := set_of_sub_functions E (product E E)).
set (pr := fun z => injection z & range (graph z) = coarse (source z)).
have [psi [psibase [prpsi ispsi]]]:
  exists psi, inc psi base & pr psi & infinite_set (source psi).
  move: (infinite_greater_countable isE) => [F [FE cFB]].
  have [f [bf [sf tf]]]: (F \Eq (product F F)).
    move:cFB; rewrite cardinal_equipotent=> eFB; eqsym.
    eqtrans (product Bnat Bnat); eqtrans Bnat.
      apply equipotent_N2_N.
    by eqsym.
  have ff: is_function f by fct_tac.
  set (y:= BL (fun z => W z f) F (product E E)).
  have pm: (sub (product F F) (product E E)) by apply product_monotone.
  have ta: (transf_axioms (fun z => W z f) F (product E E)).
     move=> t tF /=; apply pm;rewrite -tf; apply (inc_W_target ff) ;ue.
  have iy:injection y.
    apply (bl_injective ta); move: bf=> [[_ injf]_ ]; rewrite -sf; apply injf.
  exists y; split.
    rewrite /base; bw; split; [ fct_tac| rewrite /y bl_source bl_target];ee.
  split; last by rewrite /y; aw; red; rewrite cFB;apply infinite_Bnat.
  rewrite /pr; split => //;rewrite /y /BL; aw.
  have fgL: fgraph (L F (fun z : Set => W z f)) by gprops.
  set_extens t; rewrite frange_inc_rw //; bw.
    move=> [x [xF]]; bw; move=> ->; rewrite /coarse -tf.
    apply inc_W_target =>//; ue.
  move: bf=> [_ sjf]; rewrite /coarse -tf =>tt.
  move: (surjective_pr2 sjf tt) => [z []]; rewrite sf; move=> zsf <-.
  ex_tac; bw.
set (odr := opposite_order (extension_order E (product E E))).
set (ind := Zo base (fun z => pr z & sub (graph psi) (graph z))).
have oe:order (extension_order E (product E E)) by fprops.
have oo:order odr by rewrite /odr; fprops.
have so: sub ind (substrate odr) by rewrite/odr/ind; aw; apply Z_sub.
have oi: order (induced_order odr ind) by fprops.
have ii : inductive_set (induced_order odr ind).
  move=> X Xind; rewrite /total_order; aw; move => [iot tot]; awi Xind =>//.
  have Hla:forall i, inc i X -> is_function i.
    move => i iX; move: (Xind _ iX); rewrite /ind Z_rw.
    by move=> [_ [[[ok _] _] _]].
  have Hlb:forall i, inc i X -> target i = product E E.
    move => i iX; move: (Xind _ iX); rewrite /ind Z_rw/base; bw; intuition.
  have Hlc: forall x y, inc x X -> inc y X -> gle odr x y \/ gle odr y x.
    move=> x y xX yX; move: (tot _ _ xX yX);rewrite /gge; aw; apply Xind=>//.
  have Hd: forall i j, inc i X -> inc j X ->
    agrees_on (intersection2 (source i) (source j)) i j.
    move=> i j iX jX; red; ee.
        apply intersection2sub_first.
     apply intersection2sub_second.
   move=> a ;aw; move => [asi asj].
   case (Hlc _ _ iX jX)=> h; [ | symmetry ];
      apply (extension_order_pr h (x:=a)) =>//.
  have He:forall i, inc i X -> function_prop i (source i) (product E E).
    move=> i iX;red; ee.
  move: (extension_covering He Hd) => [[x [[fx [sx tx]] agx]]_].
  have xb: inc x base.
    rewrite /base; bw; ee; rewrite sx => t; srw.
    move=> [y [yX]]; move: (Xind _ yX); rewrite /ind Z_rw /base; bw; ee.
  have Hg: forall i, inc i X -> sub (graph i) (graph x).
    move=> i iX; rewrite sub_function =>//; last by apply Hla.
    move: (agx _ iX); rewrite /agrees_on; move=> [p1 [p2 p3]]; ee.
    move=> a asi; symmetry; apply p3 =>//.
  case (emptyset_dichot X)=> neX.
    exists psi; split.
      aw; rewrite /ind; apply Z_inc =>//; fprops.
    rewrite neX; move=> u ye; elim (emptyset_pr ye).
  move: neX => [y yX].
  have sgp:(sub (graph psi) (graph x)).
      apply sub_trans with (graph y); last by apply Hg.
    move: (Xind _ yX); rewrite /ind Z_rw; intuition.
  have injx: injection x.
     split=>//; move => u v;rewrite sx; srw; move=> [a [aX usa]][b [bX vsb]].
     have [z [zX [usz vsz]]]:
        (exists z, inc z X & inc u (source z) & inc v (source z)).
      move: (Hlc _ _ aX bX); rewrite /odr.
      rewrite (opposite_gle _ _ oe) (opposite_gle _ _ oe)
        ! extension_order_rw ;case; move=> [_ [_ et]];
         move: (source_extends et); [exists b | exists a ]; ee.
     move: (agx _ zX); rewrite /agrees_on; move => [_ [_ aux]].
     rewrite (aux _ usz) (aux _ vsz).
     move: (Xind _ zX); rewrite /ind Z_rw /pr; move=> [_ [[[_ iz] _] _]].
     apply iz => //.
  have rx: (range (graph x) = product (source x) (source x)).
    set_extens a; rewrite range_inc_rw//.
      move=> [b [bsx aW]]; move: bsx; rewrite sx;srw; move=> [c [cy bsc]].
      move: (agx _ cy); rewrite/agrees_on;move => [_ [_ aux]].
      rewrite (aux _ bsc) in aW.
      move: (Xind _ cy); rewrite /ind Z_rw/ pr; move=> [_ [[ic rc] _]].
      have: inc a (coarse (source c)).
        rewrite -rc aW; apply inc_W_range_graph=>//; fct_tac.
      rewrite /coarse !product_inc_rw; move=> [pa [Ps Qs]]; srw; ee; ex_tac.
    rewrite product_inc_rw sx; srw; move=> [pa [[b [bX psb]] [c [cX qsc]]]].
    have [z [zX [usz vsz]]]:
        (exists z, inc z X & inc (P a) (source z) & inc (Q a) (source z)).
      move: (Hlc _ _ bX cX).
      rewrite /odr (opposite_gle _ _ oe) (opposite_gle _ _ oe)
       ! extension_order_rw; case; move=> [_ [_ et]];
       move: (source_extends et); [exists c | exists b ]; ee.
    have :inc a (coarse (source z)) by rewrite /coarse; aw.
    move: (Xind _ zX); rewrite /ind Z_rw/ pr; move=> [_ [[ic rc] _]].
    have fz: is_function z by fct_tac.
    rewrite -rc range_inc_rw //; move=> [d [dsz]] ->.
    move: (agx _ zX); rewrite/agrees_on;move => [_ [_ aux]].
    rewrite -(aux _ dsz).
    exists d; srw; ee; ex_tac.
  have xi: (inc x ind). rewrite /ind; apply Z_inc =>//.
  exists x; split; first by aw.
  move=> z zX; move: (Xind _ zX) => zi; aw.
  move: zi; rewrite /ind Z_rw; move=> [zb _].
  rewrite /odr; aw; ee; rewrite /extends; ee.
  move: zb; rewrite /base; bw; move=>[_ [_ tz]]; rewrite tx tz; fprops.

move: (Zorn_lemma oi ii) => [x].
rewrite /maximal_element (substrate_induced_order oo so).
move=> [xi aux].
have maxp: forall u, inc u ind -> extends u x -> u = x.
   move=> u ui ue;apply aux; aw; rewrite /odr; aw.
   move: ui; rewrite /ind Z_rw; move=> [ub _].
   move: xi; rewrite /ind Z_rw; move=> [xb _].
   ee; rewrite /extends; ee.
clear aux.
move: xi; rewrite /ind Z_rw /base; bw.
move=> [[fx [ssxE txE]] [[ijx rgx] sgx]].
set (F := source x); set b:= cardinal F.
have binf:infinite_c b.
  have ss: (sub (source psi) (source x)).
    have fspi: is_function psi by move: prpsi=> [ip _]; fct_tac.
    move: (sub_graph_domain sgx); rewrite? f_domain_graph //.
  move: (sub_smaller ss); rewrite -/F -/b => p1.
  case (finite_dichot (cardinal_cardinal F)) => //.
  move=> aux; move: (le_int_is_int aux p1) => f1.
  elim (infinite_dichot2 f1 ispsi).
have bsq: (b = b *c b).
  rewrite card_mult_pr1.
  have a1: (F \Eq (coarse F)).
    rewrite /F -rgx; apply equipotent_range => //.
  rewrite /b cardinal_equipotent; eqtrans (product F F).
have cb: is_cardinal b by rewrite /b; fprops.
case (equal_or_not b E) => bE.
  by rewrite -bE power_x_2 =>//.
have bltE: (b <c E).
  split ; [move: (sub_smaller ssxE); rewrite cEE | ] => //.
have Hc: b *c 2c = b +c b by rewrite card_multC two_times_n.
have cb2b: b <=c (b *c 2c).
   by rewrite Hc; apply sum_increasing3.
have b2b2: (b *c 2c) <=c (b *c b).
  apply product_increasing2; fprops.
  have is_finite2: finite_c card_two by rewrite -inc_Bnat; fprops.
  apply (finite_le_infinite is_finite2 binf).
rewrite -bsq in b2b2.
move: (cardinal_antisymmetry1 cb2b b2b2) => b2b.
have : (b <c (cardinal(complement E F))).
  have cc: (is_cardinal (cardinal (complement E F))) by fprops.
  move: (cardinal_complement ssxE); rewrite -/F => caux.
  move: (cardinal_le_total_order2 cc cb); case; last by done.
  move => p1.
  have cbb: (b <=c b) by fprops.
  move: (sum_increasing2 cbb p1); rewrite caux -Hc -b2b cEE.
  move=> Eb; co_tac.
rewrite /cardinal_lt; move=> [lbEF _]; move: (cardinal_le_aux1 lbEF).
rewrite -(cardinal_of_cardinal cb) -eq_subset_card; move=> [Y [syc eFY]].
set (Z:= union2 F Y).
set (a1:= product F F); set (a2 := product F Y); set (a3 := product Y Z).
have dFY: disjoint F Y.
   by apply disjoint_pr; move=> u uF uy; move: (syc _ uy); srw; intuition.
have ca1: cardinal (union2 a2 a3) = b.
  have e1: F \Eq b by rewrite /b; fprops.
  have e2: Y \Eq b by eqsym.
  have e3: Z \Eq b.
    have cbb: is_cardinal (b +c b) by fprops.
    rewrite - cardinal_equipotent /Z b2b Hc (cardinal_of_cardinal cbb).
    apply card_plus_pr1 =>//.
  rewrite b2b Hc;apply card_plus_pr1.
      apply disjoint_pr; move => t; rewrite /a2 /a3; aw.
      move=> [_ [af _]][_ [ay _]]; move: (syc _ ay); srw; intuition.
    rewrite /a2 bsq card_mult_pr1; eqtrans (product b b).
  rewrite /a3 bsq card_mult_pr1; eqtrans (product b b).
have pzz: (product Z Z = union2 (product F F) (union2 a2 a3)).
  rewrite /a2 /a3 /Z; set_extens t.
    rewrite product_inc_rw !union2_rw; move=> [pt [p1 p2]].
    case p1 => r1.
      by case p2=> r2; [left | right ; left ] ;apply product_inc.
    by right; right; apply product_inc; [ | | rewrite union2_rw].
  rewrite ! union2_rw; case.
    rewrite product_inc_rw;move=> [p1 [p2 p3]].
    by apply product_inc; [| apply union2_first | apply union2_first].
  case.
     rewrite product_inc_rw;move=> [p1 [p2 p3]].
    by apply product_inc; [| apply union2_first | apply union2_second].
    rewrite product_inc_rw;move=> [p1 [p2 p3]].
    by apply product_inc; [| apply union2_second | ].
have dzz: (disjoint (product F F) (union2 a2 a3)).
  rewrite /a2 /a3 /Z; apply disjoint_pr; move=> u; aw.
  move=> [_ [pF qF]]; case.
    move=> [_ [_ qY]]; move: (syc _ qY); srw; intuition.
  move=> [_ [pY _]]; move: (syc _ pY); srw; intuition.
have: (Y \Eq (union2 a2 a3)).
   eqtrans b; first (by eqsym).
   by rewrite - cardinal_equipotent ca1; apply cardinal_of_cardinal.
move=> [x0 [bx0 [sx0 tx0]]].
set (g:= corresp Z (product E E) (union2 (graph x) (graph x0))).
have Hga: source g = Z by rewrite /g;aw.
have Hgb:graph g = (union2 (graph x) (graph x0)) by rewrite /g;aw.
have fx0: is_function x0 by fct_tac.
have Hgd: range (graph g) = coarse (source g).
  move: bx0 => [_ sjx0].
  rewrite Hga Hgb range_union2 rgx/coarse pzz -tx0 -(surjective_pr3 sjx0) //.
have Hhf: target g = product E E by rewrite /g; aw.
have Hge:domain (graph g) = (source g).
  rewrite Hgb Hga domain_union2; aw; rewrite sx0 //.
have ze: sub Z E.
  rewrite /Z; move=> t; rewrite union2_rw;case; first by rewrite/F;apply ssxE.
  move=> tY; move: (syc _ tY); srw; intuition.
have fg: is_function g.
  rewrite /g;apply is_function_pr.
      apply fgraph_union2; fprops; aw;rewrite sx0; exact dFY.
    rewrite - Hgb Hgd /coarse Hga; apply product_monotone =>//.
  by rewrite -Hgb Hge Hga.
have ig: injection g.
   have aux: forall a b c, inc (J a b) (graph x) -> inc (J c b) (graph x0) ->
    False.
     move=> u v w J1 J2.
     rewrite /disjoint in dzz; empty_tac1 v; apply intersection2_inc.
       rewrite -[product F F]/(coarse F) -rgx; dw; [ex_tac | fprops].
     rewrite -tx0; apply (inc_pr2graph_target fx0 J2).
  apply injective_pr_bis =>//; rewrite /related Hgb.
  move=> u v w; aw; case => h1; case => h2.
    apply (injective_pr3 ijx h1 h2).
    elim (aux _ _ _ h1 h2).
    elim (aux _ _ _ h2 h1).
    move: bx0 => [ijx0 _]; apply (injective_pr3 ijx0 h1 h2).
have sg: sub (graph x) (graph g) by rewrite Hgb;apply union2sub_first.
have gi: inc g ind.
  rewrite /ind /base /pr; apply Z_inc; first by bw;rewrite Hga; ee.
  ee; apply sub_trans with (graph x) =>//.
have egx: extends g x by rewrite /extends; ee; rewrite txE Hhf; fprops.
move: (maxp _ gi egx) => gz.
move: (f_equal source gz); rewrite Hga /Z => p1.
have Ye: (Y= emptyset).
   apply is_emptyset; move=> y yY; move: (syc _ yY); srw; move=> [_ yF].
   by elim yF; rewrite /F -p1; apply union2_second.
have Ye1:(cardinal Y = 0c) by rewrite Ye;apply cardinal_emptyset.
have Fe1: (b = 0c) .
  by rewrite -Ye1 -(cardinal_of_cardinal cb) cardinal_equipotent.
move: binf; rewrite Fe1 infinite_c_pr succ_zero; move=> [_ zo].
by elim card_one_not_zero.
Qed.

Lemma square_of_infinite: forall a, infinite_c a ->
   a *c a = a.
Proof.
move=> a ai.
have ca: (is_cardinal a) by move: ai => [ca _].
by rewrite -power_x_2 //; apply equipotent_inf2_inf.
Qed.

Lemma power_of_infinite: forall a n, infinite_c a -> inc n Bnat ->
  n <> 0c -> a ^c n = a.
Proof.
move=> a n ia nB nzn.
have ca: (is_cardinal a) by move: ia => [ca _].
move: (square_of_infinite ia) => aux.
move:(predc_pr nB nzn) => [qB] ->.
move: qB; set (q:= predc n). generalize q.
apply cardinal_c_induction.
  rewrite succ_zero; apply power_x_1 =>//.
by move=> m mB; rewrite (pow_succ _ (BS_succ mB)); move=> ->.
Qed.

Lemma power_of_infinite1: forall a n, infinite_c a -> inc n Bnat ->
  (a ^c n) <=c a.
Proof.
move=> a n ia nB.
have ca: (is_cardinal a) by move: ia => [ca _].
case (equal_or_not n 0c) => h.
  rewrite h power_x_0.
  have f1: finite_c card_one by rewrite -inc_Bnat; fprops.
  apply (finite_le_infinite f1 ia).
rewrite (power_of_infinite ia nB h); fprops.
Qed.

Lemma finite_family_product: forall a f, fgraph f ->
  finite_set (domain f) -> infinite_c a ->
  (forall i, inc i (domain f) -> (V i f) <=c a) ->
  (forall i, inc i (domain f) -> V i f <> 0c) ->
  (exists j, inc j (domain f) & (V j f) = a) ->
  cardinal_prod f = a.
Proof.
move=> a f fgf fsd ifa alea alnz [j0 [j0d vj0]].
set (g:= cst_graph (domain f) a).
have fgg: fgraph g by rewrite /g /cst_graph; gprops.
have df: domain f = domain g by rewrite /g/cst_graph; bw.
have le1:forall x, inc x (domain f) -> cardinal_le (V x f) (V x g).
  by move=> t tdf; rewrite /g/cst_graph; bw; apply alea.
move: (product_increasing fgf fgg df le1). rewrite/g card_pow_pr2.
set (n:= cardinal (domain f)).
have nB: (inc n Bnat) by bw.
have nz: n <> 0c by apply cardinal_nonemptyset1; exists j0 =>//.
have->: (card_pow a (domain f) = card_pow a n).
  rewrite /n;apply card_pow_pr; fprops.
rewrite (power_of_infinite ifa nB nz)=> le0.
set (j:= singleton j0).
have alc: (forall x, inc x (domain f) -> is_cardinal (V x f)).
  by move=> x xdf; move: (alea _ xdf) => [h _].
move: (alc _ j0d) => ca.
have sjd: (sub j (domain f)) by move=> t; rewrite /j singleton_rw; move=> ->.
move: (product_increasing1 fgf alc alnz sjd).
rewrite vj0 in ca.
rewrite /j trivial_cardinal_prod3 // vj0 (cardinal_of_cardinal ca).
move=> le2; co_tac.
Qed.

Lemma product2_infinite: forall a b, b <=c a ->
  infinite_c a -> b <> 0c -> a *c b = a.
Proof.
move=> a b leba ia nzb.
move :(leba) => [cb [ca _]].
have : ((a *c b) <=c (a *c a)).
  apply product_increasing2; fprops.
rewrite (square_of_infinite ia) => le1.
have le2: (a <=c (a *c b)) by apply product_increasing3.
co_tac.
Qed.

Lemma product2_infinite1: forall a b, b <=c a ->
  infinite_c a -> (a *c b) <=c a.
Proof.
move => a b leba ia.
case (equal_or_not b 0c) => h.
  rewrite h; rewrite zero_prod_absorbing.
  have f0: finite_c 0c by rewrite - inc_Bnat;fprops.
  apply (finite_le_infinite f0 ia).
move :(leba) => [_ [ca _]].
rewrite (product2_infinite leba ia h); fprops.
Qed.

Lemma product2_infinite2: forall a b, finite_c b ->
  infinite_c a -> (a *c b) <=c a.
Proof.
move => a b fb ia.
move: (finite_le_infinite fb ia) => leab.
apply (product2_infinite1 leab ia).
Qed.

Lemma notbig_family_sum: forall a f, fgraph f ->
  infinite_c a -> (cardinal (domain f)) <=c a ->
  (forall i, inc i (domain f) -> (V i f) <=c a) ->
  (cardinal_sum f) <=c a.
Proof.
move=> a f fgf ifa leda alea.
have Ha: is_cardinal a by move: ifa => [ca _].
set (g:= L (domain f) (fun _ =>a)).
have fgg: fgraph g by rewrite /g; gprops.
have dg : domain f = domain g by rewrite /g; bw.
have ale: forall x, inc x (domain f) -> cardinal_le (V x f) (V x g).
  by move=> x xdf; rewrite /g; bw; apply alea.
move: (sum_increasing fgf fgg dg ale).
rewrite sum_of_same1.
move: (product2_infinite1 leda ifa) => r1.
have ->:card_mult a (domain f) = card_mult a (cardinal (domain f)).
  symmetry;apply card_mult_pr2 => //; apply double_cardinal.
move => r2; co_tac.
Qed.

Lemma notbig_family_sum1: forall a f, fgraph f ->
  infinite_c a -> (cardinal (domain f)) <=c a ->
  (forall i, inc i (domain f) -> (V i f) <=c a) ->
  (exists j, inc j (domain f) & (V j f) = a) ->
  (cardinal_sum f) = a.
Proof.
move=> a f fgf ifa leda alea [j0 [j0d vj0]].
have ca: (is_cardinal a) by move: ifa => [ca _].
move: (notbig_family_sum fgf ifa leda alea) => le1.
have: sub (singleton j0) (domain f) by move=>t;rewrite singleton_rw; move=>->.
have: (forall x, inc x (domain f) -> is_cardinal (V x f)).
  by move=> x xdf; move: (alea _ xdf) => [ok _].
move=>p1 p2;move: (sum_increasing1 fgf p1 p2).
rewrite trivial_cardinal_sum3 // vj0 //.
rewrite (cardinal_of_cardinal ca)=> le2; co_tac.
Qed.

Lemma sum2_infinite1: forall a, infinite_c a -> a +c a = a.
Proof.
move=> a ia.
have: (card_plus a a = card_mult a card_two).
  rewrite card_multC two_times_n//.
have is_finite2: finite_c card_two by rewrite -inc_Bnat; fprops.
have le2a: cardinal_le card_two a by apply (finite_le_infinite is_finite2 ia).
have n20:card_two <> 0c by apply card_two_not_zero.
rewrite product2_infinite //; move=> <-.
Qed.

Lemma sum2_infinite: forall a b, b <=c a ->
  infinite_c a -> a +c b = a.
Proof.
move=> a b leba ia.
move :(leba) => [cb [ca _]].
have le1:(cardinal_le a (card_plus a b)) by apply sum_increasing3.
apply cardinal_antisymmetry1 =>//.
rewrite - {2} (sum2_infinite1 ia).
apply sum_increasing2; fprops.
Qed.

Lemma cardinal_comp_singl_inf: forall E x,
  infinite_set E -> cardinal E = cardinal (complement E (singleton x)).
Proof.
move=> E x iE; case (p_or_not_p (inc x E)) => xE.
  move:(cardinal_succ_pr1 E x).
  rewrite - tack_on_complement //.
  set (F:=(complement E (singleton x))) => ces.
  have cF: is_cardinal (cardinal F) by fprops.
  case (finite_dichot cF).
    rewrite (is_finite_succ cF) - ces=> h; elim (infinite_dichot2 h iE).
  by rewrite infinite_c_pr - ces; move=> [_ res].
have ->: (complement E (singleton x) = E) =>//.
set_extens t; srw; aw;[ by move=> [te _] | move=> te; ee; dneg h; ue].
Qed.

EIII-6-4 Countable sets

Definition countable_set E:= equipotent_to_subset E Bnat.

Lemma countable_prop: forall E,
  countable_set E = (cardinal E) <=c (cardinal Bnat).
Proof.
move=> E; rewrite - cardinal_le_aux2 /countable_set; fprops.
rewrite eq_subset_card.
apply iff_eq; [ move=> es;ee | intuition ].
Qed.

Lemma countable_finite_or_N: forall E, countable_set E ->
  finite_c (cardinal E) \/ cardinal E = cardinal Bnat.
Proof.
move=> E; rewrite countable_prop => leB.
case (finite_dichot (cardinal_cardinal E)) ; first by auto.
move=> [_ nf]; right.
move: (infinite_greater_countable1 nf) => le1; co_tac.
Qed.

Lemma countable_finite_or_N_b: forall E, countable_set E ->
  finite_set E \/ equipotent E Bnat.
Proof. move=> E cE; case (countable_finite_or_N cE); aw; auto. Qed.

Lemma countable_finite_or_N_c: forall E, countable_set E ->
  infinite_set E -> equipotent E Bnat.
Proof. move=> c cE; case (countable_finite_or_N_b cE) =>//.
move=> h1 h2; elim (infinite_dichot2 h1 h2).
Qed.

Theorem countable_subset: forall E F, sub E F -> countable_set F ->
  countable_set E.
Proof.
move=> E F EF; rewrite countable_prop countable_prop => h.
apply cardinal_le_transitive with (cardinal F) =>//; apply sub_smaller =>//.
Qed.

Theorem countable_product: forall f, fgraph f ->
  finite_set (domain f) ->
  (forall i, inc i (domain f) -> countable_set (V i f)) ->
  countable_set (productb f).
Proof.
move=> f fgf fsd alc; rewrite countable_prop.
set (g:= L(domain f) (fun i => cardinal (V i f))).
have ->:(cardinal (productb f) = cardinal_prod g).
  rewrite cardinal_prod_pr =>//.
set (h:= L(domain f)(fun i:Set => cardinal Bnat)).
apply cardinal_le_transitive with (cardinal_prod h).
  apply product_increasing.
          rewrite /g; gprops.
       rewrite /h; gprops.
    rewrite /g/h; bw.
  rewrite /g /h; bw; move=> x xdf; bw.
  by move: (alc _ xdf);rewrite countable_prop.
have ->: h = cst_graph (domain f) (cardinal Bnat) by [].
rewrite card_pow_pr2.
set (cb:= (cardinal Bnat)).
have ->: (card_pow cb (domain f) = card_pow cb (cardinal (domain f))).
  apply card_pow_pr;fprops.
move: infinite_Bnat. rewrite infinite_set_rw => aux.
apply power_of_infinite1; [apply aux | bw].
Qed.

Theorem countable_union: forall f, fgraph f ->
  countable_set (domain f) ->
  (forall i, inc i (domain f) -> countable_set (V i f)) ->
  countable_set (unionb f).
Proof.
move=> f fgf cs alc; rewrite countable_prop.
set d:= domain f.
apply cardinal_le_transitive
  with (cardinal_sum (L d (fun i => cardinal (V i f)))).
  apply cardinal_sum_pr1 =>//.
set (h:= L d (fun i:Set => cardinal Bnat)).
  apply cardinal_le_transitive with (cardinal_sum h).
  rewrite /h; apply sum_increasing; gprops; bw.
  move=> x xd; bw; move: (alc _ xd); rewrite countable_prop =>//.
rewrite sum_of_same1.
set (c := cardinal Bnat).
have ->: (card_mult c d = card_mult c (cardinal d)).
  symmetry;apply card_mult_pr2; fprops; apply double_cardinal.
apply product2_infinite1 =>//.
  move: cs; rewrite countable_prop //.
rewrite /c -infinite_set_rw; apply infinite_Bnat.
Qed.

Lemma card_bnat_not_zero: cardinal Bnat <> 0c.
Proof.
move=> bad.
move: (cardinal_nonemptyset bad) => h.
empty_tac1 0c.
Qed.

Theorem infinite_partition: forall E, infinite_set E ->
  exists f, partition_fam f E & (domain f) \Eq E &
    (forall i, inc i (domain f) -> (infinite_set (V i f) &
      countable_set (V i f))).
Proof.
move=> E iE; move: (infinite_greater_countable1 iE) => h1.
have iE': infinite_c (cardinal E) by split => //; apply cardinal_cardinal.
move: (product2_infinite h1 iE' card_bnat_not_zero).
rewrite card_mult_pr1 cardinal_equipotent; move=> [f [bf [sf tf]]].
move: (bf) => [injf sjf].
set (g:= L (cardinal E) (fun a => image_by_fun f
    (product (singleton a) (cardinal Bnat)))).
have ff: is_function f by fct_tac.
have ha: is_graph (graph f) by fprops.
have fgg: (fgraph g) by rewrite /g; gprops.
exists g; rewrite /g;ee; bw; [ | fprops | ].
  red;ee.
    apply mutually_disjoint_prop;bw; move=> i j y inE jnE; bw.
    rewrite /image_by_fun ! image_by_graph_rw; move=> [u [u1 u2]][v [v1 v2]].
    move:(injective_pr3 injf u2 v2) => uv.
   move: u1 v1;rewrite !product_inc_rw !singleton_rw.
   move=> [_ [u1 _]][_ [v1 _]]; rewrite -u1 -v1 uv //.
   set_extens t; srw; bw.
     move=> [y [ycE]].
     rewrite (L_V_rw _ ycE) /image_by_fun image_by_graph_rw -tf.
     move=> [x [xs xt]];apply (inc_pr2graph_target ff xt).
  move => tE.
  have tt: inc t (target f) by rewrite tf.
  move: (surjective_pr sjf tt);move=> [x [xsf jG]].
  move: xsf; rewrite sf product_inc_rw; move=> [pax [px qx]].
  ex_tac; rewrite (L_V_rw _ px) /image_by_fun image_by_graph_rw.
  exists x; ee; rewrite product_inc_rw singleton_rw; ee.
move => i inE; bw.
set (dom:= (product (singleton i) (cardinal Bnat))).
have sd: (sub dom (source f)). rewrite sf/dom; move=> t; aw.
  move=> [pt [pti qt]]; rewrite pti; ee.
have aux: (cardinal (image_by_fun f dom) = cardinal Bnat).
  aw; eqtrans dom.
    eqsym;apply (equipotent_restriction1 sd injf).
  rewrite /dom; eqtrans (cardinal Bnat).
  eqtrans (product (cardinal Bnat) (singleton i)).
  apply equipotent_product_sym.
  eqsym; apply equipotent_prod_singleton.
split.
  red; rewrite aux; apply infinite_Bnat.
by rewrite countable_prop; rewrite aux; fprops.
Qed.

Lemma countable_inv_image: forall f, surjection f ->
  (forall y, inc y (target f) ->
    countable_set (inv_image_by_fun f (singleton y))) ->
  infinite_set (target f) ->
  (source f) \Eq (target f).
Proof.
move => f sf alc it.
have ff: is_function f by fct_tac.
set (pa := L (target f) (fun z=> (inv_image_by_fun f (singleton z)))).
have upa: (unionb pa = (source f)).
  rewrite /pa; set_extens t; srw; rewrite /inv_image_by_fun;bw.
    move=> [y [tf]]; bw; aw; move=> [u []]; aw; move=> -> Jg; graph_tac.
  move => tf; exists (W t f).
  move: (inc_W_target ff tf) => wt; ee; bw; aw; ex_tac; apply W_pr3 =>//.
have md: (mutually_disjoint pa).
  rewrite /pa;apply mutually_disjoint_prop;bw.
  move=> i j y itf jtf; bw; rewrite /inv_image_by_fun; aw.
  move=> [u [ui Jg1]] [v [vi Jg2]].
  by move: ui vi; aw; move=> <- <-; rewrite- (W_pr ff Jg1) - (W_pr ff Jg2).
have fgp: fgraph pa by rewrite /pa; gprops.
move: (cardinal_sum_pr fgp).
rewrite /disjoint_union.
have: (equipotent (unionb (disjoint_union_fam pa)) (unionb pa)).
  apply equipotent_disjoint_union => //.
        rewrite /pa /disjoint_union_fam; gprops.
      rewrite/disjoint_union_fam /pa; bw.
    rewrite /disjoint_union_fam /pa; bw; move=> i idf; bw.
    eqsym; apply equipotent_prod_singleton.
  apply disjoint_union_disjoint => //.
rewrite - cardinal_equipotent; move => ->; rewrite upa.
rewrite - cardinal_equipotent.
set (cf:= L (domain pa) (fun a : Set => cardinal (V a pa))).
move => aux.
set (g:= L (domain pa) (fun _:Set => cardinal Bnat)).
have : (cardinal_le (cardinal (source f)) (cardinal_sum g)).
  rewrite aux /cf /g /pa;apply sum_increasing; [gprops | gprops | bw |].
  bw; move => x xa; bw; rewrite - countable_prop; apply alc =>//.
rewrite sum_of_same1.
have ->:(card_mult (cardinal Bnat) (domain pa) = cardinal (target f)).
  rewrite /pa; bw;
  transitivity (card_mult (cardinal Bnat) (cardinal (target f))).
    apply card_mult_pr2; [ trivial | by rewrite double_cardinal].
  set (u:= cardinal (target f)).
  rewrite card_multC; apply product2_infinite.
      apply infinite_greater_countable1 =>//.
    split; first (by apply cardinal_cardinal); done.
  apply card_bnat_not_zero.
move => le1.
have le2: (cardinal_le (cardinal (target f)) (cardinal (source f))).
  apply surjective_cardinal_le; exists f; ee.
co_tac.
Qed.

Theorem infinite_finite_subsets: forall E, infinite_set E ->
  (Zo (powerset E) (fun z => finite_set z)) \Eq E.
Proof.
move=> E inE.
have icE: infinite_c (cardinal E) by split; [apply cardinal_cardinal | exact].
set bF:=Zo _ _ .
set (T:=fun n => Zo (powerset E) (fun z => cardinal z = n)).
have le1: (forall n, inc n Bnat -> cardinal_le (cardinal (T n)) (cardinal E)).
  move=> n nB; rewrite /T.
  have cn: (cardinal n = n) by rewrite cardinal_of_cardinal; fprops.
  set (K:= Zo(set_of_functions n E)(fun z => injection z)).
  set (f:= BL (fun z => range (graph z)) K (T n)).
  have ta: transf_axioms (fun z => range (graph z)) K (T n).
    move=> z; rewrite /K /T Z_rw Z_rw; aw;move=> [[fz [sz tz]] inz].
    rewrite -tz; ee. apply f_range_graph => //.
    by symmetry;rewrite - cn -sz; aw; apply equipotent_range.
  have ff: is_function f by rewrite /f; apply bl_function => //.
  set (q:= set_of_permutations n).
  set (c := cardinal q).
  have fc: (finite_c c).
    rewrite /c /q.
    have fsn: finite_set n by rewrite /finite_set cn - inc_Bnat.
    rewrite (number_of_permutations fsn) - inc_Bnat.
    by apply BS_factorial; ue.
  have cii: (forall x, inc x (target f) ->
    cardinal (inv_image_by_fun f (singleton x)) = c).
     move=> x ; rewrite/f /c /T; aw; rewrite Z_rw; move => [xE cx].
    have : (equipotent n x) by rewrite - cx; fprops.
    move=> [x0 [bx0 [sx0 tx0]]].
    set (x1:= corresp n E (graph x0)).
    have sx1: (source x1 = n) by rewrite /x1; aw.
    have tx1: (target x1 = E) by rewrite /x1; aw.
    have ix1: (injection x1).
      have fx0: is_function x0 by fct_tac.
      apply injective_pr_bis.
         rewrite /x1; apply is_function_pr.
             fprops.
           apply sub_trans with (target x0).
             apply f_range_graph => //.
           rewrite tx0; move: xE; aw.
         aw; ue.
      rewrite /x1; aw;move=> u v w p1 p2; move: bx0 => [injx0 _].
      apply (injective_pr injx0 p1 p2).
    set iif := inv_image_by_fun _ _.
    set (g:= BL (fun z=> (compose x1 z)) q iif).
    have ta2: (transf_axioms (fun z=> (compose x1 z)) q iif).
      rewrite/q/iif; move=> z zq; rewrite /inv_image_by_fun;aw.
      ex_tac.
      move: zq; rewrite /set_of_permutations Z_rw; aw.
      move=> [[fz [sz tz]] bz].
      have cxz: (composable x1 z) by red; ee; [ fct_tac | ue].
      set (t:= compose x1 z).
      have fr: (is_function t) by rewrite /t; fct_tac.
      have tk: (inc t K).
        rewrite /K Z_rw; aw; ee; try (solve [rewrite /t; aw]).
        apply inj_compose1 =>//; [ move: bz => [iz _] => // | ue].
      have gz: is_graph (graph z) by fprops.
      have ->: (x = W t f).
        rewrite /f/t/compose; aw; rewrite compose_range //.
         have ->: (range (graph z) = n).
           move: bz => [_ bz]; rewrite (surjective_pr3 bz)=> //.
        rewrite /x1; aw; move: bx0 => [_]; rewrite /surjection/image_of_fun.
        rewrite sx0 tx0; move=> [_ h]; rewrite -h //.
      apply W_pr3 => //.
    aw.
    have fg: is_function g by rewrite /g; apply bl_function =>//.
    eqsym; exists g; ee; rewrite /g; aw.
    apply bl_bijective => //.
        rewrite /q;move=> u v; rewrite /set_of_permutations Z_rw Z_rw.
        aw; move=> [[fu [su tu]] bu][[fv [sv tv]] bv] sc.
        apply function_exten; try fct_tac; try ue.
        move=> w wsu.
        have : (W w (compose x1 u) = W w (compose x1 v)) by ue.
        have c1: composable x1 v by red; ee; try fct_tac; try ue.
        have c2: composable x1 u by red; ee; try fct_tac; try ue.
        have wsv :inc w (source v) by rewrite sv -su.
        aw; move: ix1 => [fx1 ix1]; apply ix1.
          rewrite sx1 -tu; apply inc_W_target=> //;fct_tac.
          rewrite sx1 -tv; apply inc_W_target=> //;fct_tac.
     move => y.
     rewrite /iif /q /inv_image_by_fun; aw; move=>[u []]; aw.
     move=> -> Jg.
     move:(inc_pr1graph_source ff Jg) => ysf.
     move: ysf; rewrite /f; aw => yK.
     move: (W_pr ff Jg); rewrite /f bl_W => // rg1.
     have ww: sub (range (graph y)) (range (graph x1)).
       rewrite rg1 /x1; aw.
       move: bx0 => [_ bx0]; rewrite (surjective_pr3 bx0) tx0; fprops.
     move: yK; rewrite /K Z_rw; aw; move=> [[fy [sy ty]] iy].
     rewrite -tx1 in ty; rewrite -(exists_right_composable fy ix1 ty) in ww.
     move: ww => [h [cph ch]]; exists h; ee.
     have sh: (source h = n) by rewrite -sy - ch; aw.
     have th: (target h = n) by move: cph => [_ [_ hq]]; rewrite -hq.
     have ih: injection h.
       split;first by fct_tac.
       move => v w vsh wsh sw.
       have: W v y = W w y by rewrite - ch; aw; rewrite sw.
       move:iy => [_ aux]; apply aux; [rewrite sy -sh // |rewrite sy -sh //].
    have bh: bijection h.
      apply bijective_if_same_finite_c_inj => //.
          rewrite sh th //.
        by rewrite sh/ finite_set cn -inc_Bnat.
    rewrite /set_of_permutations; apply Z_inc; aw; ee; fct_tac.
  move: (shepherd_principle ff cii).
  rewrite /f; aw; move => cK.
  case (equal_or_not n 0c) => nz.
    rewrite nz.
    have ->: (cardinal (T 0c) = card_one).
      have ->: (T 0c = singleton emptyset).
        rewrite /T;set_extens u; aw; rewrite Z_rw.
          move=> [_ aux]; rewrite (cardinal_nonemptyset aux) //.
        move => ->; aw; split; [ apply emptyset_sub_any | apply cardinal_emptyset].
      apply cardinal_singleton.
    apply finite_le_infinite; [by rewrite - inc_Bnat; fprops | exact].
  case (finite_dichot (cardinal_cardinal (T n))) => finT.
    apply finite_le_infinite =>//.
  change (cardinal_le (cardinal (T n)) (cardinal E)).
  set (K1:= cardinal (set_of_functions n E)).
  have k1E: (K1 = cardinal E).
    rewrite /K1; change (card_pow E n = cardinal E).
    have ->: (card_pow E n = card_pow (cardinal E) n)
      by apply card_pow_pr;fprops.
    apply power_of_infinite => //.
  have le1: (cardinal_le (cardinal K) (cardinal E)).
     rewrite -k1E /K1; apply sub_smaller; rewrite /K; apply Z_sub.
  apply cardinal_le_transitive with (cardinal K) => //.
  rewrite cK.
  have i2: (cardinal_le c (cardinal (T n))) by apply finite_le_infinite.
  have i3: (c <> 0c).
    rewrite /c/q.
    have fsn: finite_set n by rewrite /finite_set cn - inc_Bnat.
     rewrite (number_of_permutations fsn).
     rewrite cn; apply (factorial_nonzero nB).
  rewrite (product2_infinite i2 finT i3); fprops.
set (Fn := L Bnat (fun n => Zo (powerset E) (fun z => cardinal z = n))).
have bfu: (bF = unionb Fn).
  rewrite /bF /Fn; set_extens t; srw; bw; rewrite Z_rw.
    move=> [tp fst]; exists (cardinal t).
    red in fst; have a1: inc (cardinal t) Bnat by bw.
    ee; bw; apply Z_inc =>//.
  move=> [y [yB]]; bw; rewrite Z_rw /finite_set - inc_Bnat.
  move=> [tE] ->; ee.
  have euu: (equipotent (unionb (disjoint_union_fam Fn)) (unionb Fn)).
       apply equipotent_disjoint_union.
                rewrite /Fn/disjoint_union_fam; gprops.
              rewrite /Fn; gprops.
            rewrite /disjoint_union_fam; bw.
          rewrite /disjoint_union_fam; bw; move=> i id.
          bw; eqsym; apply equipotent_prod_singleton.
        apply disjoint_union_disjoint; rewrite /Fn; gprops.
      apply mutually_disjoint_prop; rewrite /Fn; bw.
      move=> i j y iB jB; bw; rewrite Z_rw Z_rw; move=> [_ a1][_ a2].
      rewrite -a1 -a2 //.
rewrite - cardinal_equipotent -bfu in euu.
have fgFn: (fgraph Fn) by rewrite /Fn; gprops.
move: (cardinal_sum_pr fgFn).
rewrite /disjoint_union euu => cbf.
have: (cardinal_le
       (cardinal_sum (L (domain Fn)(fun a => cardinal (V a Fn))))
    (cardinal_sum (L (domain Fn) (fun a : Set => cardinal E)))).
  apply sum_increasing; gprops; bw; rewrite /Fn;bw; move=> x xd; bw.
  change (cardinal_le (cardinal (T x)) (cardinal E)).
  apply le1 =>//.
rewrite sum_of_same1 - cbf.
have ->: (card_mult (cardinal E) (domain Fn) = cardinal E).
  rewrite /Fn; bw.
  have ->:card_mult (cardinal E)Bnat = card_mult (cardinal E) (cardinal Bnat).
    apply card_mult_pr2;[ exact | by rewrite double_cardinal].
  apply product2_infinite.
      apply infinite_greater_countable1 =>//.
    exact.
  apply card_bnat_not_zero.
have : (cardinal_le (cardinal E) (cardinal bF)).
  rewrite - eq_subset_card1 eq_subset_ex_inj.
  exists (BL (fun x => singleton x) E bF); ee; aw.
  apply bl_injective.
    move=> x xe /=; rewrite/bF; apply Z_inc; aw.
      move=> u; aw;move=> -> //.
    red; rewrite cardinal_singleton; rewrite -inc_Bnat; fprops.
  move=> u v uE vE;apply singleton_inj.
move=> lea leb.
rewrite - cardinal_equipotent; co_tac.
Qed.

Lemma infinite_finite_sequence: forall E, infinite_set E ->
 (Zo(set_of_sub_functions Bnat E) (fun z=> finite_set (source z))) \Eq E.
Proof.
move=> E iE.
have iE': infinite_c (cardinal E) by rewrite -infinite_set_rw.
set q:= Zo _ _.
rewrite - cardinal_equipotent; apply cardinal_antisymmetry1.
  move: (infinite_finite_subsets infinite_Bnat).
  set Fn:=Zo _ _; move=> fse.
  have qu:q = unionb (L Fn (fun z=> (set_of_functions z E))).
    rewrite /q/Fn; set_extens t; rewrite Z_rw;srw; bw.
      set z := Zo _ _; move=> [[ft [sst tt]] fst].
      have aux: (inc (source t) z) by rewrite /z; apply Z_inc; aw.
      ex_tac; bw; aw; ee.
    move => [y [yz]];bw; move: yz; aw; rewrite Z_rw; aw.
    move=>[yB fsy][ft [st tt]]; rewrite st;ee.
  have ze: (forall z, inc z Fn -> cardinal_le
    (cardinal (set_of_functions z E)) (cardinal E)).
    move=> z zFn; change (cardinal_le (card_pow E z) (cardinal E)).
    have ->: (card_pow E z = card_pow (cardinal E) (cardinal z)).
    apply card_pow_pr; fprops.
    apply power_of_infinite1 =>//.
    by move: zFn; rewrite /Fn Z_rw inc_Bnat/finite_set; move=> [_].
  have fg:(fgraph (L Fn (fun z : Set => set_of_functions z E))) by gprops.
  move: (cardinal_sum_pr1 fg); rewrite -qu; bw.
  set (g:= (L Fn (fun _:Set => cardinal E))).
  set f0:= (L Fn _ ).
  have fg1: (fgraph f0) by rewrite /f0; gprops.
  have fg2: (fgraph g) by rewrite /g; gprops.
  have df0g: domain f0 = domain g by rewrite /f0 /g; bw.
  have ale: (forall x, inc x (domain f0) -> cardinal_le (V x f0) (V x g)).
    by rewrite /f0/g; bw;move=> x xdf; bw; apply ze.
  move: (sum_increasing fg1 fg2 df0g ale) => le1 le2.
  move: (infinite_greater_countable1 iE) => le3.
  move: (product2_infinite1 le3 iE').
  have <-: (cardinal Fn = cardinal Bnat) by aw.
  have ->: (card_mult (cardinal E) (cardinal Fn) = card_mult (cardinal E) Fn).
    apply card_mult_pr2; fprops; apply double_cardinal.
  rewrite sum_of_same1 in le1.
  move: (cardinal_le_transitive le2 le1) => le4 le5; co_tac.
rewrite -eq_subset_card1 eq_subset_ex_inj.
have aux: forall v, inc v E ->
   transf_axioms (fun _ => v) (singleton 0c) E by move=> vE t //=.
exists (BL (fun z => (BL ((fun _:Set => z))(singleton 0c) E)) E q).
ee;aw; apply bl_injective.
  move=> z zE; rewrite /q; apply Z_inc.
    bw; aw; ee; last by apply sub_singleton; fprops.
    apply bl_function =>//.
  aw;red;rewrite cardinal_singleton -inc_Bnat; fprops.
move=> u v uE vE sv.
have zs: (inc 0c (singleton 0c)) by fprops.
move: (f_equal (W 0c) sv); aw; apply aux =>//.
Qed.

EIII-6-5 Stationary sequences


Definition stationary_sequence f :=
  fgraph f & domain f = Bnat &
  exists m, inc m Bnat & forall n, inc n Bnat -> m <=c n ->
    V n f = V m f.

Definition increasing_sequence f r:=
  fgraph f & domain f = Bnat & sub (range f) (substrate r) &
  forall n m, inc n Bnat -> inc m Bnat -> n <=c m ->
    gle r (V n f) (V m f).

Definition decreasing_sequence f r:=
  fgraph f & domain f = Bnat & sub (range f) (substrate r) &
  forall n m, inc n Bnat -> inc m Bnat -> n <=c m ->
    gle r (V m f) (V n f).

Lemma increasing_prop: forall f r, order r ->
  is_function f -> source f = Bnat -> sub (target f) (substrate r) ->
  (forall n, inc n Bnat -> gle r (W n f) (W (succ n) f)) ->
  increasing_sequence (graph f) r.
Proof.
move => f r or ff sf tf ale.
red; ee; aw.
   apply sub_trans with (target f) => //; apply f_range_graph=>//.
move=> n m nB mB nm;rewrite- (card_sub_pr nm).
set (q:= card_sub m n).
change (gle r (W n f) (W (card_plus n q) f)).
have: (inc q Bnat) by rewrite /q;hprops.
generalize q.
apply cardinal_c_induction.
   aw; fprops;order_tac; apply tf; apply inc_W_target =>//; ue.
move=> p pB le1.
rewrite (plus_via_succ _ pB).
move: (ale _ (BS_plus nB pB))=> le2; order_tac.
Qed.

Lemma decreasing_prop: forall f r, order r ->
  is_function f -> source f = Bnat -> sub (target f) (substrate r) ->
  (forall n, inc n Bnat -> gge r (W n f) (W (succ n) f)) ->
  decreasing_sequence (graph f) r.
Proof.
move => f r or ff sf tf ale.
red; ee; aw.
   apply sub_trans with (target f) => //; apply f_range_graph=>//.
move=> n m nB mB nm;rewrite- (card_sub_pr nm).
set (q:= card_sub m n).
change (gle r (W (card_plus n q) f) (W n f)).
have: (inc q Bnat) by rewrite /q;hprops.
generalize q.
apply cardinal_c_induction.
   aw; fprops;order_tac; apply tf; apply inc_W_target =>//; ue.
move=> p pB le1.
rewrite (plus_via_succ _ pB).
move: (ale _ (BS_plus nB pB)); rewrite /gge=> le2; order_tac.
Qed.

Theorem increasing_stationary: forall r, order r ->
  (forall X, sub X (substrate r) -> nonempty X ->
     exists a, maximal_element (induced_order r X) a) =
  (forall f, increasing_sequence f r -> stationary_sequence f).
Proof.
move=> r or;apply iff_eq.
  move=> hyp f [fgf [df [rf incf]]]; rewrite /stationary_sequence;ee.
  have Ha: is_graph f by fprops.
  have ner: (nonempty (range f)).
    exists (V 0c f); dw; exists 0c.
    apply fdomain_pr1=>//; rewrite df; fprops.
  move: (hyp _ rf ner) => [a];rewrite /maximal_element; aw;dw.
  move=> [[x Jg] alv].
  move:(pr2_V fgf Jg); aw => avf.
  move:(inc_pr1_domain Jg); rewrite df => xB; ex_tac.
  move=> n nB; aw; awi xB.
  move=> lexn; move: (incf _ _ xB nB lexn) => aux; rewrite -avf; apply alv.
  aw; dw; [ue | ex_tac | exists n; apply fdomain_pr1 =>//; ue].
move=> h X Xsr neX.
set (T:= fun x => Zo X (fun y => glt r x y)).
case (emptyset_dichot (productb (L X T))) => pe.
  have [x [xX Tx]]: (exists x, inc x X & T x = emptyset).
    apply exists_proof => eh.
    have p1: (fgraph (L X T)) by gprops.
    have p2: (forall i, inc i (domain (L X T)) -> nonempty (V i (L X T))).
      bw;move=> i iX; bw;case (emptyset_dichot (T i))=> //ie; elim (eh i);ee.
    move: (product_nonempty p1 p2); rewrite pe; apply not_nonempty_empty.
  exists x;red; ee;aw=> t xt; move:(iorder_gle1 xt) => xt1.
  move: (iorder_gle3 xt) => [_ tX].
  ex_middle w; empty_tac1 t; apply Z_inc =>//; split;ee.
move:pe=> [y yp].
have p1: (forall x, inc x X -> glt r x (V x y)).
  move: yp; aw; last (by gprops);move=> [fgy [dy]]; rewrite dy; bw => iVV x xX.
  by move: (iVV _ xX); rewrite /T; bw; rewrite Z_rw; move=> [_].
have p2: (forall x, inc x X -> inc (V x y) X).
  move: yp; aw; last (by gprops);move=> [fgy [dy]]; rewrite dy; bw => iVV x xX.
  by move: (iVV _ xX); rewrite /T; bw; rewrite Z_rw; move=> [ok _].
move:neX => [y0 y0X].
move: (integer_induction_stable y0X p2).
move:(induction_defined_pr (fun n : Set => V n y) y0); simpl.
set f:= induction_defined _ _.
move=> [sf [[ff _] [f0 fn]]] tfX.
have p3: (forall n, inc n Bnat -> glt r (W n f) (W (succ n) f)).
  move=> n nB; rewrite fn //; apply p1; apply tfX; apply inc_W_target=>//; ue.
have p4: (forall n, inc n Bnat -> gle r (W n f) (W (succ n) f)).
  by move=> n nB; move: (p3 _ nB)=> [ok _].
have s2: sub (target f) (substrate r) by apply sub_trans with X =>//.
move:(h _ (increasing_prop or ff sf s2 p4)) => [_ [_ [m [mB sm]]]].
have sB: (inc (succ m) Bnat) by hprops.
have lemsm: (cardinal_le m (succ m)) by apply is_le_succ; fprops.
move: (sm _ sB lemsm). move: (p3 _ mB); rewrite /W.
by move=> h1 h2; rewrite h2 in h1; move: h1=> [_].
Qed.

Theorem decreasing_stationary: forall r, total_order r ->
  (worder r) =
  (forall f, decreasing_sequence f r -> stationary_sequence f).
Proof.
move=> r tor; apply iff_eq => hyp.
  move=> f [fgf [df [rf incf]]]; rewrite /stationary_sequence;ee.
  have Ha: is_graph f by fprops.
  have ner: (nonempty (range f)).
    exists (V 0c f); dw; exists 0c.
    apply fdomain_pr1=>//; rewrite df; fprops.
  move: hyp=> [or wor]; move: (wor _ rf ner) => [y[]]; aw;dw.
  move=> [x Jg] al; move:(pr2_V fgf Jg); aw => avf.
  move:(inc_pr1_domain Jg); rewrite df => xB; ex_tac.
  move=> n nB; aw; awi xB.
  move=> lexn; move: (incf _ _ xB nB lexn) => aux; rewrite -avf.
  have vr: inc (V n f) (range f) by apply inc_V_range =>//; ue.
   move: (iorder_gle1 (al _ vr)) => h.
  rewrite -avf in aux; order_tac.
set (r':= opposite_order r).
have or: order r by move: tor => [or _].
split =>//; move=>x xsr nex.
move: (total_order_lattice (total_order_sub tor xsr)) => la.
have srsr': (substrate r = substrate r') by rewrite /r'; aw.
have aux: (forall f : Set, increasing_sequence f r' -> stationary_sequence f).
  move=> f fi; apply hyp; move : fi => [p1 [p2 [p3 p4]]]; red; ee; try ue.
  move=> n m nB mB nm; move: (p4 _ _ nB mB nm); rewrite /r';bw.
have oi:order (induced_order r x) by fprops.
have or': (order r') by rewrite /r'; fprops.
rewrite -(increasing_stationary or') in aux.
rewrite -srsr' in aux; move: (aux _ xsr nex) => [a].
rewrite /r'.
have ->: (induced_order (opposite_order r) x =
    opposite_order (induced_order r x)) by apply opposite_induced.
rewrite maximal_opposite // => mi.
move: (lattice_directed la) => [_ ld].
exists a; apply (left_directed_mimimal ld mi).
Qed.

Theorem finite_increasing_stationary: forall r, order r ->
  finite_set (substrate r) ->
  (forall f, increasing_sequence f r -> stationary_sequence f).
Proof.
move=> r or fs. rewrite - (increasing_stationary or).
move=> X Xsr neX; apply finite_set_maximal; [fprops | aw | aw].
apply (sub_finite_set Xsr fs).
Qed.

Theorem noetherian_induction: forall r F, order r ->
  (forall X, sub X (substrate r) -> nonempty X ->
    exists a, maximal_element (induced_order r X) a) ->
  sub F (substrate r) ->
  (forall a, inc a (substrate r) -> (forall x, glt r a x -> inc x F)
    -> inc a F)
  -> F = substrate r.
Proof.
move=> r F or p1 p2 p3.
set (c := complement (substrate r) F).
case (emptyset_dichot c) => ce.
  apply extensionality => //; move=> x xsr; ex_middle xsf.
  empty_tac1 x; rewrite /c; srw; ee.
have cs: sub c (substrate r) by rewrite /c; apply sub_complement.
move: (p1 _ cs ce) => [a]; rewrite / maximal_element; aw; move => [ac am].
have aux: (forall y, glt r a y -> inc y F).
  move=> y xy; ex_middle w.
  have yc: (inc y c) by rewrite /c; srw;ee; order_tac.
  move: xy => [xy nxy]; elim nxy.
  have ham: gle (induced_order r c) a y by aw; ee.
  by rewrite (am _ ham).
move: (p3 _ (cs _ ac) aux). move: ac; rewrite /c; srw; intuition.
Qed.

End InfiniteSets.
Export InfiniteSets.