Library sset9

Theory of Sets EIII-5 Properties of integers

Copyright INRIA (2009-2013) Apics; Marelle Team (Jose Grimm).

Require Import ssreflect ssrfun ssrbool eqtype ssrnat.
Require Export sset8.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Ltac cotac1 := match goal with
    | Ha: inc ?b Bnat, Hb: ?a <c (succ ?b) |- ?a <=c ?b
     => by apply /(card_lt_succ_leP Ha)
    | Ha: inc ?b Bnat, Hb: ?a <=c ?b |- ?a <c (succ ?b)
     => by apply /(card_lt_succ_leP Ha)
    | Ha: inc ?a Bnat, Hb: succ ?a <=c ?b |- ?a <c ?b
     => by apply /(card_le_succ_ltP _ Ha)
    | Ha: inc ?a Bnat, Hb: ?a <c ?b |- succ ?a <=c ?b
     => by apply /(card_le_succ_ltP _ Ha)
end.

Module IntegerProps.

EIII-5-1 Operations on integers and finite sets

Functions on nat

Lemma Bsum_M0le a b: inc a Bnat -> inc b Bnat->
  a <=c (a +c b).
Proof. move=> ca cb; apply: csum_M0le; fprops. Qed.

Lemma Bprod_M1le a b: inc a Bnat -> inc b Bnat->
   b <> \0c -> a <=c (a *c b).
Proof. move=> ca cb; apply: cprod_M1le; fprops. Qed.

Lemma Bnat_to_ell a b: inc a Bnat -> inc b Bnat ->
  [\/ a = b, a <c b | b<c a].
Proof. move=> aB bB; apply: card_le_to_ell; fprops. Qed.

Lemma Bnat_to_el a b: inc a Bnat -> inc b Bnat ->
  a <=c b \/ b <c a.
Proof. move=> aB bB; apply: card_le_to_el; fprops. Qed.

Lemma Bnat_to_ee a b: inc a Bnat -> inc b Bnat ->
  a <=c b \/ b <=c a.
Proof. move=> aB bB; apply: card_le_to_ee; fprops. Qed.

Lemma csum_trivial4 f a:
  card_sum (restr f (singleton a)) = cardinal (Vg f a).
Proof.
have <-: Vg (restr f (singleton a)) a = Vg f a by bw; fprops.
apply: csum_trivial2; rewrite restr_d //.
Qed.

Lemma cprod_trivial4 f a:
  card_prod (restr f (singleton a)) = cardinal (Vg f a).
Proof.
have <-: Vg (restr f (singleton a)) a = Vg f a by bw ; fprops.
apply: cprod_trivial2; rewrite restr_d //.
Qed.

Lemma csum_increasing6 f j: cardinal_fam f ->
  inc j (domain f) -> (Vg f j) <=c (card_sum f).
Proof.
move=> cf jd.
move: (csum_increasing1 cf (set1_sub jd)).
by rewrite csum_trivial4 (card_card (cf _ jd)).
Qed.

Lemma cprod_increasing6 f j: cardinal_fam f -> card_nz_fam f ->
  inc j (domain f) -> (Vg f j) <=c (card_prod f).
Proof.
move=> cf alnz jd.
move: (cprod_increasing1 cf alnz (set1_sub jd)).
by rewrite cprod_trivial4 (card_card (cf _ jd)).
Qed.

Lemma induction_sum0 f a b: (~ inc b a) ->
  card_sum (restr f (a +s1 b)) =
  card_sum (restr f a) +c (Vg f b).
Proof. move => nba; exact: (csumA_setU1 (Vg f) nba). Qed.

Lemma induction_prod0 f a b: (~ inc b a) ->
  card_prod (restr f (a +s1 b)) =
  (card_prod (restr f a)) *c (Vg f b) .
Proof. move => nba; exact: (cprodA_setU1 (Vg f) nba). Qed.

Lemma induction_sum1 f a b:
  domain f = a +s1 b -> (~ inc b a) ->
  card_sum f = card_sum (restr f a) +c (Vg f b).
Proof.
by move=> df nba; rewrite - (induction_sum0 _ nba) -df card_sum_gr.
Qed.

Lemma induction_prod1 f a b:
  domain f = a +s1 b -> (~ inc b a) ->
  card_prod f = card_prod (restr f a) *c (Vg f b).
Proof.
by move=> df nba; rewrite - (induction_prod0 _ nba) - df - card_prod_gr.
Qed.

Definition of a finite family of integers

Definition finite_int_fam f:=
  (allf f (inc ^~Bnat)) /\ finite_set (domain f).

A finite sum or product of integers is an integer

Section FiniteIntFam.
Variable f: Set.
Hypothesis fif: finite_int_fam f.

Lemma finite_sum_finite_aux x:
  sub x (domain f) -> inc (card_sum (restr f x)) Bnat.
Proof.
move: fif => [alB fsd] sxd.
move: (sub_finite_set sxd fsd) => fsx.
move: x fsx sxd.
apply: finite_set_induction0.
  move=> _;rewrite csum_trivial; fprops; bw; fprops.
move=> a b ap nba st.
move: (alB _ (st _ (setU1_1 b a))) => vb.
rewrite induction_sum0 =>//.
apply: BS_sum =>//; apply: ap; apply: sub_trans st; fprops.
Qed.

Lemma finite_product_finite_aux x:
  sub x (domain f) -> inc (card_prod (restr f x)) Bnat.
Proof.
move: fif => [alB fsd] sxd.
have fsx:=(sub_finite_set sxd fsd).
move: x fsx sxd.
apply: finite_set_induction0.
  rewrite cprod_trivial;fprops; bw; fprops.
move=> a b ap nba st.
rewrite induction_prod0 =>//.
have ha:= (@sub_setU1 b a) ; have hb:= (setU1_1 b a).
exact: (BS_prod (ap (sub_trans ha st)) (alB _ (st _ hb))).
Qed.

Theorem finite_sum_finite: inc (card_sum f) Bnat.
Proof.
rewrite - card_sum_gr;apply: finite_sum_finite_aux;fprops.
Qed.

Theorem finite_product_finite: inc (card_prod f) Bnat.
Proof.
rewrite - card_prod_gr; apply: finite_product_finite_aux; fprops.
Qed.

End FiniteIntFam.

Finite unions and products of finite sets are finite sets

Lemma finite_union_finite f:
  (allf f finite_set) -> finite_set (domain f) -> finite_set (unionb f).
Proof.
move=> alf fsd.
set (g:= Lg (domain f) (fun a => cardinal (Vg f a))).
have dg: (domain g = domain f) by rewrite /g; bw.
have fif: (finite_int_fam g).
  split => //; last by ue.
    rewrite /g;fprops.
  by red; rewrite dg /g; move=> i idf; bw;apply /BnatP; apply: alf.
move: (csum_pr1 f) (finite_sum_finite fif) ; rewrite -/g => f2 xB.
by apply/card_finite_setP; apply: (BS_le_int f2).
Qed.

Lemma finite_product_finite_set f: (allf f finite_set)
  -> finite_set (domain f) -> finite_set(productb f).
Proof.
move=> alf fsd.
set (g:= Lg (domain f) (fun a => cardinal (Vg f a))).
have dg: (domain g = domain f) by rewrite /g;bw.
red;rewrite cprod_pr//; apply: Bnat_hi.
apply: finite_product_finite; split => //;last by ue.
by red; bw; move=> i idf; bw; apply /BnatP;apply: alf.
Qed.

EIII-5-2 Strict inequalities between integers

If a<b there is a strictly positive c such that c=a*b

Lemma strict_pos_P1 a: inc a Bnat ->
  (a <> \0c <-> \0c <c a).
Proof.
move => aB; split => h; first by apply : card_ne0_pos; fprops.
by move: h => [_ /nesym].
Qed.

Lemma strict_pos_P a: inc a Bnat ->
  (\0c <> a <-> \0c <c a).
Proof.
by move => aB; apply:(iff_trans _ (strict_pos_P1 aB)); split; apply nesym.
Qed.

Theorem card_ltP a b: inc a Bnat -> inc b Bnat ->
  (a <c b <-> exists c, [/\ inc c Bnat, c <> \0c & a +c c = b]).
Proof.
move=> aB bB; split.
  move=> [ab nab]; move: (BS_diff a bB) => pa; ex_tac.
    by apply: cdiff_nz.
  by rewrite (cardinal_setC1 ab).
move=> [c [cB cnz <-]].
move: (card_lt_succ aB); rewrite (Bsucc_rw aB) => asa.
have p2: (a +c \1c) <=c (a +c c).
   apply: csum_Mlele; fprops; apply: card_ge1; fprops.
co_tac.
Qed.

Compatibility of sum and product with strict order

Lemma csum_Mlelt a b a' b':
  inc a' Bnat -> inc b' Bnat->
  a <=c a' -> b <c b' -> (a +c b) <c (a' +c b').
Proof.
move=> a'B b'B aa' bb'.
have bB: inc b Bnat by Bnat_tac.
move/ (card_ltP bB b'B):bb' => [c [cB cnz <-]].
apply: (@card_le_ltT _ (a' +c b)).
   apply: csum_Mlele; fprops.
by rewrite csumA; apply card_ltP;fprops; exists c.
Qed.

Lemma csum_Mlteq a a' b:
  inc b Bnat -> inc a' Bnat ->
  a <c a' -> (a +c b) <c (a'+c b).
Proof.
move=> bB a'B aa'; rewrite csumC (csumC a' b); apply: csum_Mlelt; fprops.
Qed.

Lemma csum_Meqlt a a' b:
  inc b Bnat -> inc a' Bnat ->
  a <c a' -> (b +c a) <c (b +c a').
Proof.
by rewrite (csumC b) (csumC b); exact:csum_Mlteq.
Qed.

Lemma csum_M0lt a b: inc a Bnat -> inc b Bnat -> \0c <c b -> a <c a +c b.
Proof.
move => aB bB bp.
rewrite -{1} (csum0r (CS_Bnat aB)); apply:csum_Meqlt => //.
Qed.
Lemma finite_sum4_lt a b: inc b Bnat ->
   a <> \0c -> b <c (b +c a).
Proof.
move=> bB anz.
rewrite - csum2_pr2b.
have az: \0c <c cardinal a.
  split; first by apply: czero_least; fprops.
  by apply: nesym;apply:cardinal_nonemptyset0.
rewrite csumC.
move: (CS_Bnat bB) => cb.
case: (finite_dichot (CS_cardinal a)).
  move /BnatP => aB; move: (csum_Mlteq bB aB az); aw.
move => ia.
apply: card_lt_leT (csum_M0le b (proj1 ia)).
apply: finite_lt_infinite; fprops.
Qed.

Lemma cprod_Mlelt a b a' b':
  inc a' Bnat -> inc b' Bnat->
  a <=c a' -> b <c b' -> a' <> \0c ->
  (a *c b) <c (a' *c b').
Proof.
move=> a'B b'B aa' bb'.
have bB: inc b Bnat by Bnat_tac.
move /(card_ltP bB b'B):bb' => [c [cB cnz <-]] anz.
apply: (@card_le_ltT _ (a' *c b)).
  apply: cprod_Mlele; fprops.
move: (BS_prod a'B cB) => pB.
rewrite cprod_sumDl; apply /card_ltP; fprops;ex_tac.
by apply: cprod2_nz.
Qed.

Theorem finite_sum_lt f g:
  finite_int_fam f -> finite_int_fam g -> domain f = domain g ->
  (forall i, inc i (domain f) -> (Vg f i) <=c (Vg g i)) ->
  (exists2 i, inc i (domain f) & (Vg f i) <c (Vg g i)) ->
  (card_sum f) <c (card_sum g).
Proof.
move=> fif fig df ale [i ifg lti].
move: (fif)(fig)=> [f2 f3] [g2 g3].
have idg: inc i (domain g) by rewrite -df.
move: (setC1_K ifg) => dtc; symmetry in dtc.
have incd: ~ (inc i (complement (domain f) (singleton i))).
  by move=> /setC1_P [_ ]; aw => aux; case: aux.
have sd: sub ((domain f) -s1 i) (domain f) by apply: sub_setC.
have sdg: sub ((domain g) -s1 i) (domain g) by apply: sub_setC.
rewrite (induction_sum1 dtc incd).
rewrite df in dtc incd; rewrite (induction_sum1 dtc incd).
have afB: inc (Vg f i) Bnat by apply: f2.
have agB: inc (Vg g i) Bnat by apply: g2.
apply: csum_Mlelt =>//.
  apply: finite_sum_finite_aux=>//.
apply: csum_increasing;fprops; bw; first by ue.
move=> x xd; bw; rewrite - ?df;fprops.
Qed.

Theorem finite_product_lt f g:
  finite_int_fam f -> finite_int_fam g -> domain f = domain g ->
  (forall i, inc i (domain f) -> (Vg f i) <=c (Vg g i)) ->
  (exists2 i, inc i (domain f) & (Vg f i) <c (Vg g i)) ->
  card_nz_fam g ->
  (card_prod f) <c (card_prod g).
Proof.
move=> fif fig df ale [i ifg lti] alne.
move: (fif)(fig)=> [f2 f3] [g2 g3].
have idg: inc i (domain g) by rewrite -df.
have afB: inc (Vg f i) Bnat by apply: f2.
have agB: inc (Vg g i) Bnat by apply: g2.
have sd: sub ((domain f) -s1 i) (domain f) by apply: sub_setC.
have sdg: sub ((domain g) -s1 i) (domain g) by apply: sub_setC.
have incd: ~ (inc i ((domain f) -s1 i)).
  by move=> /setC1_P [_ ]; aw => aux; case: aux.
move: (setC1_K ifg) => dtc; symmetry in dtc.
rewrite (induction_prod1 dtc incd).
rewrite df in dtc incd; rewrite (induction_prod1 dtc incd).
apply: cprod_Mlelt =>//.
      apply: finite_product_finite_aux=>//.
  apply: cprod_increasing;fprops; bw; first by ue.
  move=> x xd; bw=>//; rewrite - ?df;fprops.
apply/cprod_nzP; fprops.
red;rewrite restr_d; fprops.
move=> j jdg; move: (jdg) => /setC1_P [jd _]; bw;apply: (alne _ jd).
Qed.

Lemma cprod_M1lt a b: inc a Bnat -> inc b Bnat ->
  a <> \0c -> \1c <c b -> a <c (a *c b).
Proof.
move=> aB bB naz c1b.
move: (CS_Bnat aB) => ca.
move: (cprod_Mlelt aB bB (card_leR ca) c1b naz).
by rewrite cprod1r.
Qed.

Compatibility of power and order

Lemma cpow_nz a b: a<> \0c -> (a ^c b) <> \0c.
Proof.
move=> anz;rewrite - cpow_pr2; apply /cprod_nzP ; red; bw => t tb; bw.
Qed.

Lemma cpow2_nz x: \2c ^c x <> \0c.
Proof. apply: cpow_nz; fprops. Qed.

Lemma cpow_Mltle a a' b:
  inc a' Bnat -> inc b Bnat->
  a <c a' -> b <> \0c -> (a ^c b) <c (a' ^c b).
Proof.
move=> a'B bB aa' nzb.
move: (cpred_pr bB nzb) => [pB bs].
have nza': a'<> \0c.
  by move => h; rewrite h in aa'; apply: (card_lt0 aa').
case: (equal_or_not a \0c).
  move=> ->; rewrite cpow0x //; split.
    move: (BS_pow a'B bB) => poB; apply: czero_least; fprops.
  apply: nesym; apply: cpow_nz;fprops.
move => nz.
rewrite bs (pow_succ a pB)(pow_succ a' pB).
have p1: a <=c a' by move: aa' => [ok _].
have p2: (cpred b) <=c (cpred b) by fprops.
move: (BS_pow a'B pB) => ca'.
move: (cpow_Mlele nz p1 p2) => p3.
apply: (cprod_Mlelt ca' a'B p3 aa').
apply: cpow_nz;fprops.
Qed.

Lemma cpow_Mlelt a b b':
  inc a Bnat -> inc b' Bnat->
  b <c b' -> \1c <c a -> (a ^c b) <c (a ^c b').
Proof.
move=> aB b'B bb' l1a.
have anz: a <> \0c by move: l1a=> [/card_ge1P [_ /nesym h] _].
have bB: inc b Bnat by Bnat_tac.
move: bb' => /(card_ltP bB b'B) [c [cB cnz <-]].
have ca:cardinalp a by fprops.
move:(cpow_Mle1 ca cnz) => le1.
rewrite cpow_sum2; apply: cprod_M1lt; fprops.
  apply: cpow_nz; fprops.
co_tac.
Qed.

Lemma cpow_M1lt a b: cardinalp a -> \1c <c b -> a <c (b ^c a).
Proof.
move => ca [ /card_ge1P [ww /nesym h] bn1].
apply(card_lt_leT (cantor ca)).
apply: cpow_Mlele; fprops;apply: card_ge2; fprops;co_tac.
Qed.

Injectivity of sum and product

Lemma csum_simplifiable_left a b b':
  inc a Bnat -> inc b Bnat -> inc b' Bnat ->
  a +c b = a +c b' -> b = b'.
Proof.
move=> aB bB bB' eql.
have laa: a <=c a by fprops.
case: (Bnat_to_ell bB bB') =>// aux.
  by move: (csum_Mlelt aB bB' laa aux)=> [_ h].
by move: (csum_Mlelt aB bB laa aux)=> [_ []].
Qed.

Lemma csum_simplifiable_right a b b':
  inc a Bnat -> inc b Bnat -> inc b' Bnat ->
  b +c a = b' +c a -> b = b'.
Proof.
move=> aB bB b'B;
rewrite csumC (csumC b' a).
by apply: csum_simplifiable_left.
Qed.

Lemma cprod_simplifiable_left a b b':
  inc a Bnat -> inc b Bnat -> inc b' Bnat ->
  a <> \0c -> a *c b = a *c b' -> b = b'.
Proof.
move=> aB bB bB' naz eql.
have laa: a <=c a by fprops.
case: (Bnat_to_ell bB bB') =>// aux.
  by move: (cprod_Mlelt aB bB' laa aux naz)=> [_ h].
by move: (cprod_Mlelt aB bB laa aux naz)=> [_ []].
Qed.

Lemma cprod_simplifiable_right a b b':
  inc a Bnat -> inc b Bnat -> inc b' Bnat ->
  a <> \0c -> b *c a = b' *c a -> b = b'.
Proof.
by move=> aB bB b'B;rewrite cprodC (cprodC b' a);apply: cprod_simplifiable_left.
Qed.

cardinal difference

Lemma cdiff_wrong a b: a <=c b -> a -c b = \0c.
Proof.
by move => [_ _ ab]; rewrite /card_diff (setC_T ab) cardinal_set0.
Qed.

Lemma cdiff_pr a b:
  b <=c a -> b +c (a -c b) = a.
Proof. apply: cardinal_setC1. Qed.

Lemma cdiff_pr0 a b: inc a Bnat-> inc b Bnat ->
  b <=c a -> (inc (a -c b) Bnat /\ b +c (a -c b) = a).
Proof. move=> aB bB h; split; [ fprops | by apply: cdiff_pr]. Qed.

Lemma cdiff_pr1 a b: inc a Bnat-> inc b Bnat ->
  (a +c b) -c b = a.
Proof.
move=> aB bB.
move: (BS_sum aB bB)=> sB.
move: (Bsum_M0le bB aB); rewrite csumC=> aux.
move: (cdiff_pr aux); rewrite csumC=> aux'.
apply: (csum_simplifiable_right bB (BS_diff _ sB) aB aux').
Qed.

Lemma cdiff_rpr a b:
  b <=c a -> (a -c b) +c b = a.
Proof. by move=> leaB;rewrite csumC; apply: cdiff_pr. Qed.

Lemma cdiff_pr2 a b c: inc a Bnat-> inc b Bnat ->
  a +c b = c -> c -c b = a.
Proof. by move=> aB bB h; move: (cdiff_pr1 aB bB); rewrite h. Qed.

Lemma cdiff_pr3 a b n:
   inc n Bnat -> a <=c b -> b <=c n -> (n -c b) <=c (n -c a).
Proof.
move => mB le1 le2.
have bB:=(BS_le_int le2 mB).
have aB:=(BS_le_int le1 bB).
have dB:=(BS_sum (BS_diff a bB) (BS_diff b mB)).
rewrite - {2} (cdiff_pr le2).
rewrite -{2} (cdiff_pr le1) - csumA (csumC a) (cdiff_pr1 dB aB) csumC.
apply:(csum_M0le _ (CS_diff n b)).
Qed.

Lemma cdiff_pr7 a b c:
  a <=c b -> b <c c -> inc c Bnat -> (b -c a) <c (c -c a).
Proof.
move => le1 lt2 cB.
have bB:= (BS_lt_int lt2 cB).
have aB:= (BS_le_int le1 bB).
move:(BS_diff a bB) (BS_diff b cB) => ha hb.
rewrite -(cdiff_pr (proj1 lt2)) - {2}(cdiff_pr le1) - csumA csumC.
rewrite (cdiff_pr1 (BS_sum ha hb) aB);apply: (csum_M0lt ha hb).
split; [ apply: czero_least;fprops | apply: (nesym (cdiff_nz lt2))].
Qed.

Lemma cardinal_setC4 E A: sub A E ->
  finite_set E -> cardinal (E -s A) = (cardinal E) -c (cardinal A).
Proof.
move => AE fe.
move: (cardinal_setC AE) =>cc.
have ccEA: cardinalp (cardinal (E -s A)) by fprops.
have ccA: cardinalp (cardinal A) by fprops.
symmetry; rewrite - cc csumC.
move: fe => /BnatP; rewrite - cc => sB.
apply: cdiff_pr1 =>//.
   apply: (Bnat_in_sum ccEA sB).
rewrite csumC in sB;apply: (Bnat_in_sum ccA sB).
Qed.

Lemma cdiff_n_n a: a -c a = \0c.
Proof. by rewrite /card_diff setC_v cardinal_set0. Qed.

Lemma cdiff_n_0 a: inc a Bnat -> a -c \0c = a.
Proof. move=> aB; apply: cdiff_pr2; fprops; aw; fprops. Qed.

Lemma cdiff_pr4 a b a' b': inc a Bnat-> inc b Bnat ->
  inc a' Bnat-> inc b' Bnat ->
  a <=c b -> a' <=c b' ->
  (b +c b') -c (a +c a') = (b -c a) +c (b' -c a').
Proof.
move=> aB bB a'B b'B ab a'b'.
apply: cdiff_pr2; [ fprops | fprops |].
have aux: ((b -c a) +c b') +c a = b' +c b.
  by rewrite (csumC _ b') - csumA cdiff_rpr.
by rewrite (csumC a a') csumA - (csumA _ _ a') (cdiff_rpr a'b') aux csumC.
Qed.

Lemma cdiffA a b c:
  inc a Bnat -> inc b Bnat -> inc c Bnat ->
  (b +c c) <=c a -> (a -c b) -c c = a -c (b +c c).
Proof.
move=> aB bB cB h.
move: (cdiff_pr h) => aux.
apply: cdiff_pr2 =>//; first by fprops.
symmetry; apply: cdiff_pr2; fprops.
by rewrite - csumA csumC (csumC c b).
Qed.

Lemma cpred_pr4 a: cardinalp a -> cpred a = a -c \1c.
Proof.
move=> ca.
case: (finite_dichot ca).
  case/finite_succ => anz.
    rewrite /cpred /card_diff anz setU_0 setC_T ?cardinal_set0; fprops.
  move: anz => [y fy sy].
  rewrite sy - {2} (succ_of_finite fy) (card_succ_pr4 (CS_finite_o fy)).
  by rewrite /cpred (succo_K (proj1 fy)) (cdiff_pr1 _ BS1) //; apply /BnatP.
rewrite /cpred /card_diff.
move => pa; move: (proj1 (proj1 pa)) => oa.
move: (infinite_card_limit2 pa)=> pb.
move /(limit_ordinal_P1 oa): pb => [ane <-].
move: (ord_ne_pos oa ane) => /(ord_ltP oa) a0.
move: (ordinal_irreflexive oa) => ia.
rewrite -[a -s \1c] /(a -s1 \0o) -{1} (card_card ca); apply /card_eqP.
have: a +s1 a \Eq ((a -s1 \0o) +s1 \0o).
  rewrite (setC1_K a0); eqsym;move: pa => [] //.
by move /(setU1_injective_card2 ia (@setC1_1 \0o a)).
Qed.

Lemma cdiff_nz1 a b: inc a Bnat -> inc b Bnat ->
  (succ b) <=c a -> a -c b <> \0c.
Proof.
move=> aB bB lesba; apply: cdiff_nz => //; apply /card_le_succ_ltP => //.
Qed.

Lemma cdiff_A1 a b: inc a Bnat -> inc b Bnat ->
  (succ b) <=c a -> cpred (a -c b) = a -c (succ b).
Proof.
move=> aB bB; rewrite (Bsucc_rw bB) => h'.
rewrite - cdiffA; fprops; apply: cpred_pr4; fprops.
Qed.

Lemma cdiff_le_symmetry a b:
  b <=c a -> (a -c b) <=c a.
Proof.
move=> ba; move:(cdiff_pr ba) => aux.
rewrite -{2} aux csumC; apply: csum_M0le; apply:CS_diff.
Qed.

Lemma cdiff_lt_symmetry n p: inc p Bnat ->
  n <c p -> (cpred (p -c n)) <c p.
Proof.
move=> pB ltnp.
have snz := (cdiff_nz ltnp).
move: ltnp => [lenp _].
move: (cdiff_pr0 pB (BS_le_int lenp pB) lenp) => [sf aux].
move: (cpred_pr sf snz)=> [aa bb].
apply /(card_le_succ_ltP _ aa); rewrite - bb; apply: (cdiff_le_symmetry lenp).
Qed.

Lemma double_diff n p: inc n Bnat ->
  p <=c n -> n -c (n -c p) = p.
Proof.
move=> nB lepn.
move: (BS_le_int lepn nB) => pB.
apply: cdiff_pr2; [exact pB | fprops | apply: cdiff_pr=>//].
Qed.

Lemma csucc_diff a b: inc a Bnat -> inc b Bnat ->
  (succ b) <=c a -> a -c b = succ (a -c (succ b)).
Proof.
move=> aB bB aux; move: (BS_succ bB) => sB.
apply: cdiff_pr2 ; fprops.
have sb: inc (a -c (succ b)) Bnat by fprops.
rewrite (Bsucc_rw sb) - csumA.
have->: (\1c +c b = succ b) by rewrite (Bsucc_rw bB) csumC.
apply: cdiff_rpr =>//.
Qed.

Lemma cardinal_complement_image1 f: injection f ->
  (cardinal ((target f) -s (image_of_fun f))) +c (cardinal (source f))
  = cardinal (target f).
Proof.
move => injf.
set A:= (image_of_fun f).
have ->: (cardinal (source f) = cardinal A).
  apply /card_eqP;exists (restriction_to_image f).
  rewrite /restriction_to_image/restriction2; red;aw; split => //.
  by apply: (restriction_to_image_fb injf).
symmetry; rewrite csumC.
set B:= (target f) -s A.
have p0: sub A (target f) by apply: fun_image_Starget; fct_tac.
have <-: A \cup B = target f by apply: setU2_Cr.
rewrite csum2_pr2a csum2_pr2b csum2_pr5 //;apply: set_I2Cr.
Qed.

Lemma cardinal_complement_image f: injection f ->
  finite_set (target f) ->
    cardinal ((target f) -s (image_of_fun f)) =
    (cardinal (target f)) -c (cardinal (source f)).
Proof.
move=> injf fst.
move: (cardinal_complement_image1 injf).
move: fst => /BnatP fb h.
rewrite - h in fb |- *.
have aB := (Bnat_in_sum (CS_cardinal (source f)) fb).
have cB:= (Bnat_in_sum2 (CS_cardinal (target f -s image_of_fun f)) fb).
by symmetry;apply: cdiff_pr1.
Qed.


Lemma Bnat_le_R a: inc a Bnat -> a <=N a.
Proof. move => aB; split;fprops. Qed.

Lemma Bnat_le_T a b c: a <=N b -> b <=N c -> a <=N c.
Proof.
move /Bnat_order_leP => ab /Bnat_order_leP bc; apply /Bnat_order_leP.
move: Bnat_order_wor=> [[or wor] _]; order_tac.
Qed.

Lemma Bnat_le_A a b: a <=N b -> b <=N a -> a = b.
Proof.
move /Bnat_order_leP => ab /Bnat_order_leP ba.
move: Bnat_order_wor=> [[or wor] _]; order_tac.
Qed.

Lemma Bnato_to_el a b: inc a Bnat -> inc b Bnat ->
  a <=N b \/ b <N a.
Proof.
move=> aB bB.
move:Bnat_order_wor=> [wor sr].
move: (worder_total wor)=> [or prop].
case: (equal_or_not b a).
  move=>->; left; apply /Bnat_order_leP.
  order_tac; by rewrite sr.
rewrite sr in prop; case: (prop _ _ aB bB); move /Bnat_order_leP.
  by left.
by move => pa pb; right; split.
Qed.

Lemma csum_le_simplifiable a b c:
  inc a Bnat -> inc b Bnat -> inc c Bnat->
  (a +c b) <=c (a +c c) -> b <=c c.
Proof.
move=> aB bB cB abc.
case: (Bnat_to_el bB cB) => // ltcb.
move: (csum_Mlelt aB bB (card_leR (CS_Bnat aB)) ltcb)=> h; co_tac.
Qed.

Lemma csum_lt_simplifiable a b c:
  inc a Bnat -> inc b Bnat -> inc c Bnat->
  (a +c b) <c (a +c c) -> b <c c.
Proof.
move=> aB bB cB [abc nac]; split.
  apply: (csum_le_simplifiable aB bB cB abc).
by dneg bc; rewrite bc.
Qed.

Lemma cprod_le_simplifiable a b c:
  inc a Bnat -> inc b Bnat -> inc c Bnat-> a <> \0c ->
  (a *c b) <=c (a *c c) -> b <=c c.
Proof.
move=>aB bB cB naz abc.
case: (Bnat_to_el bB cB) => // ltcb.
move: (cprod_Mlelt aB bB (card_leR (CS_Bnat aB)) ltcb naz)=> h; co_tac.
Qed.

Lemma cprod_lt_simplifiable a b c:
  inc a Bnat -> inc b Bnat -> inc c Bnat-> a <> \0c ->
  (a *c b) <c (a *c c) -> b <c c.
Proof.
move=> aB bB cB naz [abc nac]; split.
   by apply: (cprod_le_simplifiable aB).
by dneg bc; rewrite bc.
Qed.

Lemma cdiff_pr5 a b c: inc a Bnat -> inc b Bnat -> inc c Bnat ->
  (a +c c) -c (b +c c) = a -c b.
Proof.
move => aB bB cB.
case: (Bnat_to_ee aB bB) => ab.
  symmetry; rewrite (cdiff_wrong ab) (cdiff_wrong) //.
  by apply:csum_Mleeq.
by apply:cdiff_pr2; fprops; rewrite csumA (csumC _ b) cdiff_pr.
Qed.

Lemma cdiff_pr6 a b: inc a Bnat -> inc b Bnat ->
  (succ a) -c (succ b) = a -c b.
Proof.
move=> aB bB; rewrite !Bsucc_rw //;apply: cdiff_pr5 =>//; fprops.
Qed.

Lemma cdiff_increasing2 a b c: inc a Bnat -> inc b Bnat ->
  c <=c (a +c b) -> (c -c b) <=c a.
Proof.
move=> aB bB cab.
move: (BS_le_int cab (BS_sum aB bB)) => cB.
case: (Bnat_to_ee cB bB) => cb; first by rewrite cdiff_wrong; fprops.
apply: (csum_le_simplifiable (a:= b)); fprops.
rewrite csumC in cab; rewrite cdiff_pr //.
Qed.

Lemma cdiff_increasing3 a b c: inc a Bnat ->inc c Bnat ->
  b <=c c -> c <c (a +c b) -> (c -c b) <c a.
Proof.
move=> aB cB bc cab.
move: (BS_le_int bc cB) => bB.
apply: (csum_lt_simplifiable (a:= b)); fprops.
rewrite csumC in cab; rewrite cdiff_pr //.
Qed.

EIII-5-3 Intervals in sets of integers

Definition Bintcc a b := interval_cc Bnat_order a b.
Definition Bint a:= interval_co Bnat_order \0c a.
Definition Bintc a:= Bintcc \0c a.
Definition Bint1c a:= Bintcc \1c a.

Definition Bint_cco a b :=
  graph_on cardinal_le (interval_cc Bnat_order a b).

Lemma Bintc_i b x: inc x (Bintc b) -> x <=c b.
Proof. by move /Bint_ccP => [_ [_ _ h]]. Qed.

Lemma BintcP b: inc b Bnat -> forall x, (inc x (Bintc b) <-> x <=c b).
Proof.
move=> bB x; split; first by apply: Bintc_i.
move => h;apply /(Bint_ccP1 BS0 bB); split => //; apply: czero_least; co_tac.
Qed.

Lemma Bint1cP b: inc b Bnat -> forall x,
  (inc x (Bint1c b) <-> (x <> \0c /\ x <=c b)).
Proof.
move=> bB x; apply: (iff_trans (Bint_ccP1 BS1 bB x)).
split.
  move => [pa pb];split => //.
  move=> bz; rewrite bz in pa.
  move: (card_le0 pa); apply: card1_nz.
move => [x0 xb]; split => //.
by move: xb => [cb _ _]; apply: card_ge1.
Qed.

Lemma Bint1cPb b: inc b Bnat -> forall x,
  (inc x (Bint1c b) <-> (\1c <=c x /\ x <=c b)).
Proof. move=> aB x; apply: (Bint_ccP1 BS1 aB). Qed.

Lemma Bint_S a b: sub (Bintcc a b) Bnat.
Proof. rewrite /Bintcc /interval_cc (proj2 Bnat_order_wor); apply: Zo_S. Qed.

Lemma Bint_S1 a: sub (Bint a) Bnat.
Proof. rewrite /Bint /interval_co (proj2 Bnat_order_wor); apply: Zo_S. Qed.

Lemma Bint_i a x: inc x (Bint a) -> x <c a.
Proof. by move => /Bint_coP [_ [[_ _ ha] hb]]; split. Qed.

Lemma BintP a: inc a Bnat -> forall x,
  (inc x (Bint a) <-> x <c a).
Proof.
move=> aB x; split; first by apply:Bint_i.
move => xa; apply/(Bint_coP1 BS0 aB); split => //.
apply: czero_least; co_tac.
Qed.

Lemma BintsP a: inc a Bnat -> forall x,
  (inc x (Bint (succ a)) <-> x <=c a).
Proof.
move=> aB x; apply: (iff_trans (Bint_coP1 BS0 (BS_succ aB) x)); split.
  by move => [_ [pa pb]]; apply /(card_lt_succ_leP aB); split.
move => lxa;split; first by apply: czero_least; co_tac.
by apply /(card_lt_succ_leP aB).
Qed.

Lemma Bint_co_cc p: inc p Bnat -> Bintc p = Bint (succ p).
Proof.
move => pB; set_extens x.
  by move/(BintcP pB) /(BintsP pB).
by move /(BintsP pB)/(BintcP pB).
Qed.

Lemma Bint_co00: Bint \0c = emptyset.
Proof. apply /set0_P=> t; move /(BintP BS0); apply: card_lt0. Qed.

Lemma Bint_co01: (inc \0o (Bint \1c) /\ Bint \1c = singleton \0c).
Proof.
have zi: inc \0c (Bint \1c).
   apply/(BintP BS1); apply: card_lt_01.
split => //.
apply: set1_pr => // z /(BintP BS1).
rewrite - succ_zero; move/(card_lt_succ_leP BS0);apply: card_le0.
Qed.

Lemma Bint_cc00: Bintc \0c = singleton \0c.
Proof.
by rewrite -(proj2 Bint_co01) - succ_zero (Bint_co_cc BS0).
Qed.

Lemma Bintc_M a b: inc b Bnat ->
  a <=c b -> sub (Bintc a) (Bintc b).
Proof. move=> bB ab t /(Bintc_i) ta; apply /(BintcP bB); co_tac. Qed.

Lemma Bintc_M1 a: inc a Bnat ->
  sub (Bintc a) (Bintc (succ a)).
Proof. move=> aB;apply: Bintc_M; fprops. Qed.

Lemma Bint_si a: inc a Bnat ->
  inc a (Bint (succ a)).
Proof. move=> aB; apply /(BintsP aB); fprops. Qed.

Lemma Bint_M a: inc a Bnat -> sub (Bint a) (Bint (succ a)).
Proof.
move=> aB t /(BintP aB) tx; apply/(BintsP aB); co_tac.
Qed.

Lemma Bint_M1 a b: inc b Bnat -> a <=c b -> sub (Bint a) (Bint b).
Proof.
move=> bB ab r /Bint_i ra; apply /(BintP bB); co_tac.
Qed.

Lemma Bint_pr4 n: inc n Bnat ->
  ( ((Bint n) +s1 n = (Bint (succ n)))
    /\ ~(inc n (Bint n))).
Proof.
move=> nB.
split; last by move/(BintP nB) => [_].
set_extens t.
   case/setU1_P.
    by apply:Bint_M.
    by move => ->; apply:Bint_si.
move /(BintsP nB) => tn; apply/setU1_P.
case: (equal_or_not t n); first by right.
by move => ntn; left; apply/(BintP nB); split.
Qed.

Lemma Bint_pr5 n (si := Bintcc \1c n): inc n Bnat ->
  ( (si +s1 \0c = Bintc n) /\ ~(inc \0c si)).
Proof.
move=> nB; split.
  set_extens x.
    case /setU1_P; first by move /(Bint_ccP1 BS1 nB) => [_]/(BintcP nB).
    move => ->; apply /(BintcP nB); fprops.
  move /(BintcP nB) => h; apply /setU1_P.
  case: (equal_or_not x \0c) => xz; [right => //| left => // ].
  apply /(Bint_ccP1 BS1 nB);split => //;apply: card_ge1 => //;co_tac.
move /(Bint_ccP1 BS1 nB) => [h _].
move: card_lt_01 => xx; co_tac.
Qed.

Lemma incsx_intsn x n:
  inc n Bnat ->
  inc x (Bint n) -> inc (succ x) (Bint (succ n)).
Proof.
move => nB.
move/(BintP nB) => lin.
apply /(BintsP nB); apply /card_le_succ_lt0P => //; co_tac.
Qed.

Lemma inc0_int01: inc \0c (Bint \1c).
Proof. by apply /(BintP); fprops; apply: card_lt_01. Qed.

Lemma inc0_int02: inc \0c (Bint \2c).
Proof. by apply /(BintP); fprops; apply: card_lt_02. Qed.

Lemma cardinal_c_induction5 (r:property) a:
  inc a Bnat -> r \0c ->
  (forall n, n <c a -> r n -> r (succ n))
  -> (forall n, n <=c a -> r n).
Proof.
move=> aB r0 rs.
have rss: forall n,
  inc n (Bint a) -> r n -> r (succ n).
  by move=> n /(BintP aB); apply: rs.
move: (cardinal_c_induction3_v (r:=r) BS0 aB r0 rss) => h n na.
by apply: h; apply /(BintcP aB).
Qed.

Section IntervalBnatwo.
Variables (a b: Set).
Hypotheses (aB:inc a Bnat)(bB:inc b Bnat).

Lemma Binto_wor: worder_on (Bint_cco a b) (Bintcc a b).
Proof.
move: cardinal_le_wor => wo.
have r: (forall x, inc x (interval_cc Bnat_order a b) -> x <=c x).
  move=> x xb; exact (card_leR (CS_Bnat (Bint_S xb))).
by move: (wordering_pr wo r).
Qed.

Lemma Binto_gleP x y:
  gle (Bint_cco a b) x y <->
    [/\ inc x (Bintcc a b), inc y (Bintcc a b) & x <=c y].
Proof. apply: graph_on_P1. Qed.

Lemma Binto_gleP2 x y:
  gle (Bint_cco a b) x y <-> [/\ a <=c x, y <=c b & x <=c y].
Proof.
split.
  move/Binto_gleP=> [] /(Bint_ccP1 aB bB) [pa pb] /(Bint_ccP1 aB bB) [pc pd] pe.
  done.
move => [pa pb pc]; apply/Binto_gleP; split => //;
  apply /(Bint_ccP1 aB bB); split => //; co_tac.
Qed.

End IntervalBnatwo.

Definition Bint_co a :=
  graph_on cardinal_le (Bint a).

Section IntervalBnatwo1.
Variable (a: Set).
Hypothesis (aB:inc a Bnat).

Lemma Bintco_wor: worder_on (Bint_co a) (Bint a).
Proof.
move: cardinal_le_wor => wo.
have r: forall x, inc x (Bint a) -> x <=c x.
  move=> x xi; move: (Bint_S1 xi) => xB; fprops.
by move: (wordering_pr wo r).
Qed.

Lemma Bintco_gleP x y: (gle (Bint_co a) x y <-> (x <=c y /\ y <c a)).
Proof.
split.
  by move /graph_on_P1 => [] /(BintP aB) xa /(BintP aB) ya xy.
move=> [xy ya]; apply/graph_on_P1; split => //;
  apply /(BintP aB) => //; co_tac.
Qed.

End IntervalBnatwo1.

Lemma segment_Bnat_order x: inc x Bnat ->
  segment Bnat_order x = interval_co Bnat_order \0c x.
Proof.
move=> xB; set_extens t; move /Zo_P => [pa pb];apply:Zo_i => //.
  move: pb => [] /Bnat_order_leP [tn aa bb] cc.
  split; first by apply/Bnat_order_leP; split; fprops.
  split; first by apply/Bnat_order_leP; split; fprops.
  exact.
by case: pb.
Qed.

Definition rest_plus_interval a b :=
  Lf(fun z => z +c b)(Bintcc \0c a) (Bintcc b (a +c b)).

Definition rest_minus_interval a b :=
  Lf(fun z => z -c b) (Bintcc b (a +c b)) (Bintcc \0c a).

Theorem restr_plus_interval_is a b: inc a Bnat -> inc b Bnat->
 [/\ bijection (rest_plus_interval a b) ,
   bijection (rest_minus_interval a b),
   (rest_minus_interval a b) = inverse_fun (rest_plus_interval a b) &
   order_isomorphism (rest_plus_interval a b)
  (Bint_cco \0c a)
  (Bint_cco b (a +c b))].
Proof.
move=> aB bB.
move: BS0 => zB.
move: (BS_sum aB bB) => abB.
set E1:= Bintc a.
set E2:= Bintcc b (a +c b).
have tap: lf_axiom (fun z => z +c b) E1 E2.
  move => z /(BintcP aB) za; apply/(Bint_ccP1 bB abB); split.
    rewrite csumC; apply: csum_M0le; fprops.
  apply: csum_Mlele=>//; fprops.
have tam: lf_axiom (fun z => z -c b) E2 E1.
  move => z /(Bint_ccP1 bB abB) [bt tab]; apply /(BintcP aB).
  move: (BS_diff b (BS_le_int tab abB)) => sB; apply: cdiff_increasing2 =>//.
set (f:= rest_plus_interval a b).
set (g:= rest_minus_interval a b).
have ff:function f by apply: lf_function.
have fg:function g by apply: lf_function.
have sf:source f = target g by rewrite lf_source lf_target.
have sg:source g = target f by rewrite lf_source lf_target.
have cfg:f \coP g by [].
have cgf: g \coP f by [].
have c1: g \co f = identity (source f).
  apply: function_exten; [fct_tac | fprops | aw | symmetry; aw | ].
  rewrite compf_s;move=> x xsf /=.
  rewrite (identity_V xsf); aw.
  move: xsf; rewrite lf_source=> xs.
  rewrite (lf_V tap xs) (lf_V tam (tap _ xs)).
  rewrite cdiff_pr1 =>//; apply: (Bint_S xs).
have c2: f \co g = identity (source g).
  apply: function_exten ; [fct_tac | fprops | aw | symmetry; aw | ].
  rewrite compf_s;move=> x xsg /=.
  rewrite (identity_V xsg) (compf_V cfg xsg).
  move: xsg; rewrite lf_source=> xs.
  rewrite (lf_V tam xs).
  have xB: inc x Bnat by apply :(Bint_S xs).
  move: xs => /(Bint_ccP1 bB abB) [bx xaB].
  have aux: inc (x -c b) (Bintcc \0c a).
    apply/(BintcP aB); apply: cdiff_increasing2 =>//.
  rewrite (lf_V tap aux) csumC cdiff_pr //.
move: (bijective_from_compose cgf cfg c1 c2)=> [bf bg gif]; split => //.
have sp : E1 = source (rest_plus_interval a b).
  by rewrite /rest_plus_interval; aw.
move: (Binto_wor \0c a) => [[o1 _ ] sr1].
move: (Binto_wor b (a +c b))=> [[o2 _ ] sr2].
red;rewrite /bijection_prop sr1 sr2 lf_source lf_target;split => //.
move=> x y /=; rewrite lf_source => xsf ysf.
rewrite (lf_V tap xsf) (lf_V tap ysf).
apply: (iff_trans (Binto_gleP \0c a x y)).
symmetry.
apply (iff_trans (Binto_gleP b (a +c b) (x +c b) (y +c b))).
split; move => [pa [pb pc]];split => //; try (apply: tap => //).
  apply: (csum_le_simplifiable bB (Bint_S xsf) (Bint_S ysf)).
  by rewrite csumC (csumC b y).
apply: csum_Mlele=>//; fprops.
Qed.

Lemma card_Bintc a: inc a Bnat ->
  cardinal (Bintc a) = succ a.
Proof.
move: a; apply: cardinal_c_induction.
  rewrite succ_zero Bint_cc00; apply: cardinal_set1.
move => n nB.
move: (BS_succ nB) => snB.
rewrite (Bint_co_cc nB) (Bint_co_cc snB).
have [<- aux]:= (Bint_pr4 snB).
by rewrite card_succ_pr ; [move => -> |].
Qed.

Lemma Bint_pr1 a: inc a Bnat -> a <> \0c ->
  Bintcc \0c (cpred a) = Bint a.
Proof.
move: BS0 => zB.
move=> aB naz;move: (cpred_pr aB naz) => [fp ass].
rewrite {2} ass - Bint_co_cc //.
Qed.

Lemma card_Bintcp a: inc a Bnat -> a <> \0c ->
  cardinal (Bintc (cpred a)) = a.
Proof.
move=> aB naz.
by move: (cpred_pr aB naz) => [fp ass]; rewrite card_Bintc.
Qed.

Lemma card_Bint a: inc a Bnat ->
  cardinal (Bint a) = a.
Proof.
move=> aB; case: (equal_or_not a \0c).
  move => ->; rewrite Bint_co00; apply: cardinal_set0.
move=> h; rewrite - Bint_pr1//; apply: card_Bintcp=>//.
Qed.

Theorem card_Bintcc a b: a <=N b ->
  cardinal (Bintcc a b) = succ (b -c a).
Proof.
move=> [aB bB ab].
move: (cdiff_pr ab) (BS_diff a bB) => aux cB.
rewrite csumC in aux.
set (c:= b -c a) in *.
move: (restr_plus_interval_is cB aB) => [b1 _ _ _].
have eq: (Bintcc \0c c) \Eq (Bintcc a b).
  exists (rest_plus_interval c a); rewrite /rest_plus_interval.
  red;rewrite lf_source lf_target; split => //; ue.
by rewrite -(card_Bintc cB); apply /card_eqP; eqsym.
Qed.

Lemma card_Bint1c a: inc a Bnat ->
  cardinal (Bint1c a) = a.
Proof.
move => aB.
case: (equal_or_not a \0c).
  move=> ->.
  have ->: (Bint1c \0c = emptyset).
    rewrite /Bint1c.
    apply /set0_P => y; move /(Bint1cPb BS0)=> [c1y cy0].
    move: (card_leT c1y cy0) card_lt_01 => h1 h2;co_tac.
  apply: cardinal_set0.
move => anz.
have aux1: \1c <=c a by apply: card_ge1; fprops.
have aux: \1c <=N a by split;fprops.
have so: inc (a -c \1c) Bnat by move: BS1 => i1; fprops.
rewrite card_Bintcc // Bsucc_rw // csumC.
apply: cdiff_pr; fprops.
Qed.

Lemma finite_Bintcc a b: finite_set (Bintcc a b).
Proof.
apply/card_finite_setP.
case: (p_or_not_p (a <=N b)) => h.
  rewrite card_Bintcc //; move: h => [aB bB _]; fprops.
have ->: (Bintcc a b) = emptyset.
   apply /set0_P => t /Zo_hi [] /Bnat_order_leP [pa _ pc]
      /Bnat_order_leP [_ pe pf].
   case: h; split;fprops; co_tac.
rewrite cardinal_set0; fprops.
Qed.

Lemma finite_Bint a: finite_set (Bint a).
Proof.
have aux:sub (Bint a) (Bintcc \0c a).
   by move => t /Zo_P [pa [pb [pc _]]]; apply /Zo_P.
have : (finite_set (Bintcc \0c a)) by apply: finite_Bintcc.
apply: (sub_finite_set aux).
Qed.

Lemma infinite_Bnat_alt: ~(finite_set Bnat).
Proof.
move /BnatP =>h.
move: (sub_smaller (Bint_S (a:=\0c) (b:=cardinal Bnat))).
rewrite (card_Bintc h).
by move /(card_le_succ_ltP _ h) => [_].
Qed.

Lemma isomorphism_worder_finite r r':
  total_order r -> total_order r' ->
  finite_set (substrate r) -> (substrate r) \Eq (substrate r') ->
  exists! f, order_isomorphism f r r'.
Proof.
move=> tor tor' fs.
move /card_eqP => sc.
have fs': finite_set (substrate r') by red; rewrite - sc.
move:(finite_set_torder_wor tor fs) (finite_set_torder_wor tor' fs').
move => wor wor'; move: (isomorphism_worder wor wor') => iw.
have aux: forall u v f, order_isomorphism f u v ->
   segmentp v (range (graph f)) /\ order_morphism f u v.
  move => f u v h; split; last by apply:order_isomorphism_w.
  move: h => [_ or' [[injf sjf] sf tf] pf].
  by rewrite (surjective_pr3 sjf) tf; apply: substrate_segment.
case: iw.
  move => [f [[pa mf] pc]]; exists f; split.
    move: (order_morphism_fi mf) => injf.
    move: mf => [o1 o2 [ff sf tf] pf]; split => //; split => //.
    apply: bijective_if_same_finite_c_inj; [ by rewrite sf tf | ue| exact].
 by move => f' xx; apply:pc; apply: aux.
move => [f [[pa mf] pc]].
have oi: (order_isomorphism f r' r).
  move: (order_morphism_fi mf) => injf.
  move: mf => [o1 o2 [ff sf tf] pf].
   have bf: bijection f by apply: bijective_if_same_finite_c_inj;
     rewrite ? sf ?tf;[ symmetry; apply: sc| exact| exact].
   split=> //.
move: (inverse_order_is oi)=> oii.
exists (inverse_fun f); split => //.
move => f' h1.
rewrite (pc _ (aux _ _ _ (inverse_order_is h1))).
move: h1 => [_ _ [[[ff _] _] _ _] _ ].
by rewrite (ifun_involutive ff).
Qed.

Theorem finite_ordered_interval r: total_order r ->
  finite_set (substrate r) ->
  exists! f, order_isomorphism f r
    (Bint_cco \1c (cardinal (substrate r))).
Proof.
move=> tot fs.
move: (fs); move/BnatP => fs'.
move: (Binto_wor \1c (cardinal (substrate r))) => [pa pb].
move: (card_Bint1c fs').
move/card_eqP;rewrite /Bint1c - pb; fprops.
move => h;apply: (isomorphism_worder_finite tot (worder_total pa) fs).
by eqsym.
Qed.

Theorem finite_ordered_interval1 r: total_order r ->
  finite_set (substrate r) ->
  exists !f, order_isomorphism f r
    (Bint_co (cardinal (substrate r))).
Proof.
move=> tor fs.
move: (finite_set_torder_wor tor fs)=> wor.
move: (fs) => /BnatP fs'.
move: (card_Bint fs') => /card_eqP.
rewrite - (proj2 (Bintco_wor _)) // => e.
move: (worder_total (proj1(Bintco_wor (cardinal (substrate r))))) => tor'.
by apply: (isomorphism_worder_finite tor tor' fs); eqsym.
Qed.

A finite sum or product can be defined by induction

Lemma induction_on_sum a f: inc a Bnat ->
  let iter := fun n=> card_sumb (Bint n) f
    in (iter a) +c (f a) = (iter (succ a)).
Proof.
move=> aB /=.
by move: (Bint_pr4 aB) => [<- aux];symmetry; apply csumA_setU1.
Qed.

Lemma induction_on_prod a f: inc a Bnat ->
  let iter := fun n=> card_prodb (Bint n) f
    in (iter a) *c (f a) = (iter (succ a)).
Proof.
move=> aB /=.
move: (Bint_pr4 aB) => [<- aux].
by symmetry; apply cprodA_setU1.
Qed.

Lemma fct_sum_rec0 f n: inc n Bnat ->
  card_sumb (Bintc n) f = (card_sumb (Bint1c n) f) +c (f \0c).
Proof.
move=> nB; move: (Bint_pr5 nB) => [<- aux].
by apply csumA_setU1.
Qed.

Lemma fct_sum_rec1 f n: inc n Bnat ->
  card_sumb (Bintcc \0c (succ n)) f
  = (card_sumb (Bintcc \0c n) (fun i=> f (succ i))) +c (f \0c).
Proof.
move=> nB.
have sB:inc (succ n) Bnat by fprops.
rewrite (fct_sum_rec0 _ sB); congr (_ +c (f \0c)).
set i1:= Bint1c _ ; set i0:= Bintcc _ _.
have p1: forall x : Set, inc x i0 -> inc (succ x) i1.
  move => t /(BintcP nB) => tn; apply /(Bint1cP sB).
  have ct: cardinalp t by co_tac.
  split; [ apply: succ_nz | apply/ (card_le_succ_succP ct )]; fprops.
rewrite /card_sumb (csum_Cn2 (I:=i0) (f:= succ)).
   congr (card_sum _); apply: Lg_exten; move=> x xi0 /=; bw; apply: p1=>//.
split => //.
    by move=> x xi; bw; apply: p1.
 move=> u v ui vi susv; apply: succ_injective1.
     move: (Bint_S ui); fprops.
   move: (Bint_S vi); fprops.
   done.
move=> y; bw; move/(Bint1cP sB) => [nyz le_s].
have fy:inc y Bnat by Bnat_tac.
move: (cpred_pr fy nyz)=> [pB ns].
exists (cpred y) => //.
apply/(BintcP nB); apply/card_le_succ_succP => //; fprops; ue.
Qed.

Lemma fct_sum_rev f n: inc n Bnat ->
  let I := (Bint (succ n)) in
  card_sumb I f = card_sumb I (fun i=> f (n -c i)).
Proof.
move=> nB I.
have snB: inc (succ n) Bnat by fprops.
set X := Lg I f.
pose g i := n -c i.
have p1: forall x, inc x I -> inc (n -c x) I.
  move=> x /(BintsP nB) => xn; apply /(BintsP nB).
  apply: cdiff_le_symmetry =>//.
rewrite /card_sumb.
have->:(Lg I (fun i : Set => f (n -c i)) = Lg I (fun z => Vg X (g z))).
  apply: Lg_exten; move=> x xI; rewrite /X /g; bw; apply: p1 =>//.
apply: csum_Cn2; split => //.
    rewrite /g/X; bw.
  move=> x y /(BintsP nB) xn /(BintsP nB) yn; rewrite /g => h.
  by rewrite - (double_diff nB xn) -(double_diff nB yn) h.
rewrite /g; bw => y /(BintsP nB) yn; rewrite -(double_diff nB yn).
exists (n -c y) => //; apply /(BintsP nB).
apply: cdiff_le_symmetry =>//; Bnat_tac.
Qed.

EIII-5-4 Finite sequences

EIII-5-5 Characteristic functions on sets


Lemma char_fun_V_aa A x: inc x A ->
  Vf (char_fun A A) x = \1c.
Proof. by move => xa; rewrite char_fun_V_a. Qed.

Lemma char_fun_V_bb A x: inc x A ->
  Vf (char_fun emptyset A) x = \0c.
Proof.
move => xa; rewrite char_fun_V_b; fprops.
by apply /setC_P; split => // /in_set0.
Qed.

Lemma char_fun_constant A B:
   sub A B -> (cstfp (char_fun A B) B) -> (A=B \/ A = emptyset).
Proof.
move=> AB p.
case: (emptyset_dichot A); [by right | move=> [u uA]; left ].
apply: extensionality=>// t tB.
ex_middle v.
have xc:inc t (B -s A) by apply /setC_P; split =>//.
case: card1_nz.
by rewrite - (char_fun_V_b AB xc)- (char_fun_V_a AB uA) (p _ _ (AB _ uA) tB).
Qed.

Lemma char_fun_setC A B x: sub A B -> inc x B ->
  Vf (char_fun (B -s A) B) x = \1c -c (Vf (char_fun A B) x).
Proof.
move=> AB xB.
have sc:sub (B -s A) B by apply: sub_setC.
case: (inc_or_not x A).
  move=> xA; rewrite char_fun_V_b //.
    rewrite char_fun_V_a //; symmetry; apply: cdiff_n_n; fprops.
  by rewrite setC_K.
move=> h.
have xc: inc x (B -s A) by apply/setC_P.
rewrite char_fun_V_a // char_fun_V_b //.
symmetry;apply: cdiff_n_0; fprops.
Qed.

Lemma char_fun_setI A A' B x: sub A B -> sub A' B -> inc x B ->
  Vf (char_fun (A \cap A') B) x
  = (Vf (char_fun A B) x) *c (Vf (char_fun A' B) x).
Proof.
move=> AB A'B xB.
have Ha:sub (A \cap A') B.
  by move=> t /setI2_P [tA _]; apply: AB.
case: (inc_or_not x A) => h.
  have cW:cardinalp (Vf (char_fun A' B) x) by apply: char_fun_V_cardinal.
  rewrite (char_fun_V_a AB h) cprod1l //.
  case: (inc_or_not x A') => xA.
    have aux:inc x (A \cap A') by apply: setI2_i.
    rewrite char_fun_V_a // char_fun_V_a //.
  have aux:inc x (B -s (A \cap A'))
    by apply /setC_P;split => //; move /setI2_P =>[_].
  rewrite char_fun_V_b // char_fun_V_b //.
  by apply /setC_P.
have aux: inc x (B -s (A \cap A'))
 by apply /setC_P;split => //; move /setI2_P =>[].
have aux2:inc x (B -s A) by fprops.
by rewrite char_fun_V_b // char_fun_V_b // cprodC cprod0r.
Qed.

Lemma char_fun_setU A A' B x: sub A B -> sub A' B -> inc x B ->
  (Vf (char_fun (A \cap A') B) x)
  +c (Vf (char_fun (A \cup A') B) x)
  = (Vf (char_fun A B) x) +c (Vf (char_fun A' B) x).
Proof.
move=> AB A'B xB.
have Ha:sub (A \cap A') B by move=> t /setI2_P [ta _]; apply: AB.
have Hb:sub (A \cup A') B by move=> t /setU2_P; case; fprops.
case: (p_or_not_p (inc x A))=> xA.
  rewrite (char_fun_V_a AB xA).
  rewrite (char_fun_V_a Hb (setU2_1 A' xA)).
  case: (p_or_not_p (inc x A'))=> xA'.
    rewrite (char_fun_V_a A'B xA') char_fun_V_a //.
     by apply: setI2_i.
  rewrite csumC; apply: f_equal.
  by rewrite ! char_fun_V_b //; apply /setC_P; split => //; move /setI2_P => [].
have Hc: inc x (B -s A) by fprops.
have Hd:inc x (B -s (A \cap A')).
  by apply /setC_P; split => //; move /setI2_P => [].
rewrite (char_fun_V_b AB Hc) (char_fun_V_b Ha Hd).
case: (p_or_not_p (inc x A')) => aux.
  have xu: inc x (A \cup A') by apply: setU2_2.
  by rewrite (char_fun_V_a Hb xu) (char_fun_V_a A'B aux).
have xc:inc x (B -s (A \cup A')).
  by apply /setC_P; split => //;move /setU2_P => [].
have xba: inc x (B -s A') by fprops.
by rewrite (char_fun_V_b Hb xc) (char_fun_V_b A'B xba).
Qed.

EIII-5-6 Euclidean Division


Lemma least_int_prop (prop:property):
  (forall x, prop x -> inc x Bnat) -> (exists x, prop x) ->
  prop \0c \/ (exists x, [/\ inc x Bnat, prop (succ x) & ~ prop x]).
Proof.
move=> pi [x xp].
set (X:=Zo Bnat prop).
have sX: sub X Bnat by apply: Zo_S.
have nX: nonempty X by exists x; apply: Zo_i=>//; apply: pi.
case: (Bnat_wordered sX nX)=> q.
   by left; move: q =>/Zo_P [_].
right; move: q=> [a [aB /Zo_hi psa /Zo_P h]]; ex_tac;fprops.
Qed.

Lemma least_int_prop1 (prop:property):
  (forall x, prop x -> inc x Bnat) -> ~(prop card_zero) ->
  (exists x, prop x) -> (exists x, [/\ inc x Bnat, prop(succ x) & ~ prop x]).
Proof.
move=> alp npz exp; case: (least_int_prop alp exp)=>// h.
Qed.

Definition card_division_prop a b q r :=
  a = (b *c q) +c r /\ r <c b.

Lemma card_division_prop_alt a b q r: inc a Bnat-> inc b Bnat ->
  inc q Bnat-> inc r Bnat -> b <> \0c ->
  (card_division_prop a b q r <->
  [/\ (b *c q) <=c a, a <c (b *c succ q) & r = a -c (b *c q)]).
Proof.
move=> aB bB qB rB nzb; rewrite /card_division_prop.
set (w:= b *c q).
rewrite Bsucc_rw // cprodC cprod_sumDr cprodC cprod1l; fprops.
have wB: inc w Bnat by rewrite /w; fprops.
split.
  move=> [av lt];split => //.
  - rewrite av; apply: csum_M0le; fprops.
  - rewrite av; apply: csum_Mlelt; fprops.
  - by symmetry;apply: cdiff_pr2 =>//; symmetry; rewrite csumC.
move=> [lwa ltas rv].
rewrite rv.
have aux: inc (b *c q +c b) Bnat by fprops.
split; first by symmetry; apply: cdiff_pr =>//.
move: ltas => /(card_ltP aB aux) [c [cB nzc s]] {aux}.
move: (cdiff_pr lwa); rewrite -rv=> aux.
apply /(card_ltP rB bB); ex_tac.
apply: (@csum_simplifiable_left w);fprops.
by rewrite csumA aux.
Qed.

Lemma card_division_unique a b q r q' r': inc a Bnat-> inc b Bnat ->
  inc q Bnat-> inc r Bnat -> inc q' Bnat-> inc r' Bnat -> b <> \0c ->
  card_division_prop a b q r -> card_division_prop a b q' r' ->
  (q = q' /\ r =r').
Proof.
move=> aB bB qB rB q'B r'B nbz.
move /(card_division_prop_alt aB bB qB rB nbz)=> [le1 lt1 e1].
move /(card_division_prop_alt aB bB q'B r'B nbz)=> [le2 lt2 e2].
suff : q = q' by move=> h; split => //; rewrite e1 e2 h.
move: (card_le_ltT le1 lt2) => lt3.
move: (card_le_ltT le2 lt1) => lt4.
move: (cprod_lt_simplifiable bB q'B (BS_succ qB) nbz lt4).
move: (cprod_lt_simplifiable bB qB (BS_succ q'B) nbz lt3).
move /(card_lt_succ_leP q'B) => pa /(card_lt_succ_leP qB) => pb; co_tac.
Qed.

Lemma card_division_exists a b: inc a Bnat-> inc b Bnat ->
  b <> \0c -> exists q r,
    [/\ inc q Bnat, inc r Bnat & card_division_prop a b q r].
Proof.
move=> aB bB nzb.
set (pp:= fun q => inc q Bnat /\ a <c (b *c q)).
have np: (forall x, pp x -> inc x Bnat) by move => x [].
have zp: (~ (pp \0c)).
   rewrite /pp; move => [_]; rewrite cprod0r.
   move=> h;apply: (card_lt0 h).
have ep: (exists x, pp x).
  rewrite /pp; exists (succ a); split; first by fprops.
  have aux: (succ a) <=c (b *c (succ a)).
     by rewrite cprodC; apply: Bprod_M1le; fprops.
  by apply /card_le_succ_ltP.
move: (least_int_prop1 np zp ep)=> [q [qB q1 q2]].
have p1: ((b *c q) <=c a).
  move: (Bnat_to_el (BS_prod bB qB) aB); case => //.
  move=> [p1 p2]; case: q2; split; [exact | split ] =>//.
move: (cdiff_pr p1); set (r:= a -c (b *c q)) => rp.
have rB: inc r Bnat by rewrite /r; apply: (BS_diff _ aB).
exists q; exists r; split => //; apply /card_division_prop_alt => //.
by split => //; move: q1=> [_].
Qed.

Definition card_quo a b := least_ordinal (fun q => a <c b *c (succ q)) a.
Definition card_rem a b := a -c (b *c (card_quo a b)).
Definition card_divides b a :=
  [/\ inc a Bnat, inc b Bnat & card_rem a b = \0c].

Notation "x %/c y" := (card_quo x y) (at level 40).
Notation "x %%c y" := (card_rem x y) (at level 40).
Notation "x %|c y" := (card_divides x y) (at level 40).

Lemma cquo_zero a: a %/c \0c = \0c.
Proof.
rewrite /card_quo /least_ordinal.
set s := Zo _ _.
have -> : s = emptyset.
  apply /set0_P => y /Zo_hi; rewrite cprodC cprod0r; apply: card_lt0.
by rewrite setI_0.
Qed.

Lemma card_division a b (q := a %/c b) (r := (a %%c b)):
  inc a Bnat -> inc b Bnat -> b <> \0c ->
  [/\ inc q Bnat, inc r Bnat & card_division_prop a b q r].
Proof.
move=> aB bB bnz.
pose p z := (a <c b *c succ z).
have ca: cardinalp a by fprops.
have oa: ordinalp a by apply:OS_cardinal.
have pa: p a.
 have aux: (succ a) <=c (b *c (succ a)).
     by rewrite cprodC; apply: Bprod_M1le; fprops.
  by apply /card_le_succ_ltP.
move: (least_ordinal1 oa pa); rewrite /p -/q.
move=> [qa qb qc].
have qd: q <=o a by split => //; exact (qc _ oa pa).
have qB: inc q Bnat.
  case: (equal_or_not q a); first by move => ->.
  move=> naq.
  have: q <o a by split.
  move /ord_ltP0 => [_ _ qe].
  move /BnatP: aB => aB; apply /BnatP;exact: (finite_o_increasing qe aB).
have rB: inc r Bnat by apply: BS_diff => //; apply: BS_prod.
split => //.
apply /card_division_prop_alt => //; split => //.
case: (p_or_not_p (q = \0c)).
  move=> ->; rewrite cprod0r; apply: czero_least; fprops.
move=> qnz; move: (cpred_pr qB qnz); set (z := (cpred q)).
move => [zB qs].
case: (card_le_to_el (CS_prod2 b q) ca) => //; rewrite qs => h.
have oz: ordinalp z by apply:OS_cardinal; fprops.
move: (qc _ oz h) => qz.
have zq : inc z q.
  have fz: finite_c z by fprops.
  rewrite qs (succ_of_finite fz) /succ_o; fprops.
case: (ordinal_irreflexive oz (qz _ zq)).
Qed.

Lemma crem_zero a: inc a Bnat -> a %%c \0c = a.
Proof. move => h; rewrite /card_rem cprodC cprod0r cdiff_n_0 //. Qed.

Lemma BS_quo a b: inc a Bnat-> inc b Bnat ->
  inc (a %/c b) Bnat.
Proof.
move => aB bB.
case: (equal_or_not b \0c) => bnz.
  rewrite bnz cquo_zero;fprops.
exact: (proj31 (card_division aB bB bnz)).
Qed.

Lemma BS_rem a b: inc a Bnat-> inc b Bnat ->
  inc (a %%c b) Bnat.
Proof.
move => aB bB.
case: (equal_or_not b \0c) => bnz.
  rewrite bnz crem_zero //.
exact: (proj32 (card_division aB bB bnz)).
Qed.

Hint Resolve BS_rem BS_quo: fprops.

Lemma cdiv_pr a b: inc a Bnat-> inc b Bnat ->
  a = (b *c (a %/c b)) +c (a %%c b).
Proof.
move => aB bB.
case: (equal_or_not b \0c) => bnz.
  rewrite bnz (crem_zero aB) cquo_zero cprod0r; aw; fprops.
by move: (card_division aB bB bnz) =>[_ _ [h _]].
Qed.

Lemma crem_pr a b: inc a Bnat-> inc b Bnat -> b <> \0c ->
  (a %%c b) <c b.
Proof.
by move => aB bB bnz; move: (card_division aB bB bnz) =>[_ _ [_]].
Qed.

Lemma cquorem_pr a b q r:
  inc a Bnat-> inc b Bnat -> inc q Bnat -> inc r Bnat ->
  card_division_prop a b q r -> (q = a %/c b /\ r = a %%c b).
Proof.
move => aB bB qB rB p'.
case: (equal_or_not b \0c) => bnz.
  move: p' => [_ ]; rewrite bnz =>h; case: (card_lt0 h).
move: (card_division aB bB bnz)=> [qqB rrB p].
apply: (card_division_unique aB bB qB rB qqB rrB bnz p' p).
Qed.

Lemma cquorem_pr0 a b q:
  inc a Bnat-> inc b Bnat -> inc q Bnat -> b <> \0c ->
   a = (b *c q) -> (q = a %/c b /\ \0c = a %%c b).
Proof.
move => aB bB qB bnz p'.
apply: cquorem_pr =>//.
  fprops.
red; rewrite -p' (bsum0r aB).
split; [ trivial | split; [ apply: czero_least | ]]; fprops.
Qed.

Lemma cdivides_pr a b:
  b %|c a -> a = b *c (a %/c b).
Proof.
move => [aB bB dv].
move: (cdiv_pr aB bB); rewrite dv.
by rewrite (bsum0r (BS_prod bB (BS_quo aB bB))).
Qed.

Lemma cdivides_pr1 a b: inc a Bnat -> inc b Bnat ->
  b %|c (b *c a).
Proof.
move=> aB bB.
move: (BS_prod bB aB) => pB.
split => //.
case: (equal_or_not b card_zero) => bnz.
  rewrite bnz cprodC cprod0r crem_zero //; fprops.
by case: (cquorem_pr0 pB bB aB bnz (refl_equal (b *c a))).
Qed.

Lemma cdivides_pr2 a b q:
  inc a Bnat -> inc b Bnat -> inc q Bnat -> b <> \0c ->
  a = b *c q -> q = a %/c b.
Proof.
move => aB bB qB nzb abq.
by case: (cquorem_pr0 aB bB qB nzb abq).
Qed.

Lemma cdivides_one a: inc a Bnat -> \1c %|c a.
Proof.
move=> aB; rewrite - (cprod1l (CS_Bnat aB)).
apply: (cdivides_pr1 aB BS1).
Qed.

Lemma cquo_one a: inc a Bnat -> a %/c \1c = a.
Proof.
move=> aB; symmetry; apply: cdivides_pr2; fprops; fprops.
rewrite cprod1l;fprops.
Qed.

Lemma cdivides_pr3 a b q:
   b %|c a -> q = a %/c b -> a = b *c q.
Proof. by move => H aux; move: (cdivides_pr H); rewrite -aux.
Qed.

Lemma cdivides_pr4 b q: inc b Bnat -> inc q Bnat -> b <> \0c ->
   (b *c q) %/c b = q.
Proof. move=> *; symmetry; apply: cdivides_pr2 =>//; fprops.
Qed.

Lemma cdivision_itself a: inc a Bnat -> a <> \0c ->
  (a %|c a /\ a %/c a = \1c).
Proof.
move=> aB anz; rewrite /card_divides.
have aux:a = a *c \1c by rewrite (cprod1r (CS_Bnat aB)).
by move: (cquorem_pr0 aB aB BS1 anz aux) => [p1 p2].
Qed.

Lemma cdivides_itself a: inc a Bnat -> a <> \0c ->
   a %|c a.
Proof. by move=> aB anz; move: (cdivision_itself aB anz) => [h _]. Qed.

Lemma cquo_itself a: inc a Bnat -> a <> \0c ->
   a %/c a = \1c.
Proof. by move=> aB anz; move: (cdivision_itself aB anz) => [ _ h]. Qed.

Lemma cdivision_of_zero a: inc a Bnat ->
  (a %|c \0c /\ \0c %/c a = \0c).
Proof.
move=> aB; rewrite /card_divides.
move: BS0 => bs0.
have aux: \0c = a *c \0c by rewrite cprod0r.
case: (equal_or_not a \0c) => anz.
  by rewrite anz cquo_zero crem_zero.
by move: (cquorem_pr0 BS0 aB BS0 anz aux) => [p1 p2].
Qed.

Lemma cdivides_trans a b a':
  a %|c a'-> b %|c a -> b %|c a'.
Proof.
move=> d1 d2.
rewrite (cdivides_pr d1) {1} (cdivides_pr d2) - cprodA.
move: d1 d2 => [p1 p2 _] [p3 p4 _].
apply: cdivides_pr1 =>//; fprops.
Qed.

Lemma cdivides_trans1 a b a':
  a %|c a' -> b %|c a
  -> a' %/c b = (a' %/c a) *c (a %/c b).
Proof.
move=> d1 d2.
move: (cdivides_pr d1).
rewrite {1} (cdivides_pr d2) - cprodA => h.
case: (equal_or_not b \0c) => bnz.
 by rewrite bnz cquo_zero cquo_zero cprod0r.
move: d1 d2 => [a'B aB _][_ bB _].
have pB: inc ((a %/c b) *c (a' %/c a)) Bnat by fprops.
rewrite - (cdivides_pr2 a'B bB pB bnz h).
by rewrite cprodC.
Qed.

Lemma cdivides_trans2 a b c: inc c Bnat ->
  b %|c a-> b %|c (a *c c).
Proof.
move=> cB ba.
have aB: (inc a Bnat) by move: ba => [h _].
move: (cdivides_pr1 cB aB) => aux.
apply: (cdivides_trans aux ba).
Qed.

Lemma cquo_simplify a b c:
  inc a Bnat -> inc b Bnat -> inc c Bnat -> b <> \0c -> c <> \0c ->
  (a *c c) %/c (b *c c) = a %/c b.
Proof.
move=> aB bB cB bnz cnz.
move: (card_division aB bB bnz)=> [qB rB []].
set q:= (a %/c b); set r := a %%c b.
move=> e1 lrb; symmetry.
move: (BS_prod aB cB)(BS_prod bB cB)(BS_prod (BS_rem aB bB) cB) => p1 p2 p3.
have dv: (card_division_prop (a *c c) (b *c c) q (r *c c)).
  split.
     rewrite (cprodC b c) - cprodA (cprodC c _).
    by rewrite - cprod_sumDr e1.
  rewrite (cprodC b c) cprodC.
  apply: cprod_Mlelt =>//; fprops.
by move: (cquorem_pr p1 p2 qB p3 dv) => [res _].
Qed.

Lemma cdivides_and_sum a a' b: b %|c a -> b %|c a'
  -> (b %|c (a +c a') /\
    (a +c a') %/c b = (a %/c b) +c (a' %/c b)).
Proof.
move=> d1 d2.
move: (cdivides_pr d1)(cdivides_pr d2)=> am bm.
set s := (a %/c b) +c (a' %/c b).
have ->: (a +c a' = b *c s).
  by rewrite /s cprod_sumDl -am -bm.
move: d1 d2 => [aB bB _][a'B _ _].
have sB:inc s Bnat by rewrite /s; fprops.
split; first by apply: cdivides_pr1 =>//.
case: (equal_or_not b \0c) => bs.
  rewrite {2} /s bs ! cquo_zero; aw; fprops.
by symmetry; apply: (cdivides_pr2 (BS_prod bB sB) bB sB bs).
Qed.

Lemma cdistrib_prod2_sub a b c: inc a Bnat -> inc b Bnat -> inc c Bnat
  -> c <=c b ->
  a *c (b -c c) = (a *c b) -c (a *c c).
Proof.
move=> aB bB cB le; symmetry; apply: cdiff_pr2; fprops.
rewrite - cprod_sumDl csumC cdiff_pr //.
Qed.

Lemma cdivides_and_difference a a' b:
  a' <=c a -> b %|c a -> b %|c a'
  -> [/\ b %|c (a -c a'), (a' %/c b) <=c (a %/c b) &
    (a -c a') %/c b = (a %/c b) -c (a' %/c b)].
Proof.
move=> le d1 d2.
move: (cdivides_pr d1)(cdivides_pr d2)=> am bm.
set s := (a %/c b) -c (a' %/c b).
move: d1 d2 => [aB bB _][a'B _ _].
move: (BS_quo aB bB)(BS_quo a'B bB) => q1 q2.
have q3: (a' %/c b) <=c (a %/c b).
  case: (equal_or_not b \0c) => bnz.
    rewrite bnz ! cquo_zero; fprops.
  rewrite am bm in le.
  apply: (cprod_le_simplifiable bB q2 q1 bnz le).
have ->: (a -c a' = b *c s).
  by rewrite /s cdistrib_prod2_sub // -am -bm.
have sB:inc s Bnat by rewrite /s; fprops.
split => //; first by apply: cdivides_pr1 =>//.
case: (equal_or_not b card_zero) => bs.
  rewrite {2} /s bs ! cquo_zero cdiff_n_n; fprops.
by symmetry; apply: (cdivides_pr2 (BS_prod bB sB) bB sB bs).
Qed.

EIII-5-7 Expansion to base b


Lemma b_power_k_large a b: inc a Bnat -> inc b Bnat ->
  \1c <c b -> a <> \0c -> exists k,
    [/\ inc k Bnat, (b ^c k) <=c a & a <c (b ^c (succ k))].
Proof.
move=> aB bB l1b naz.
set (prop:= fun k=> inc k Bnat /\ a <c (b ^c k)).
have pB:(forall x, prop x -> inc x Bnat) by move => k [].
have pz: ~(prop card_zero).
  rewrite /prop cpowx0; move=> [_ a1].
   move: (card_ge1 (CS_Bnat aB) naz)=> h; co_tac.
have exp:(exists x, prop x).
  exists a; split=> //; apply: cpow_M1lt;fprops.
move: (least_int_prop1 pB pz exp)=> [k [kN pks npk]].
ex_tac; last by move: pks => [_ res].
case: (Bnat_to_el (BS_pow bB kN) aB) => //.
by move=>h; case: npk.
Qed.

Definition expansion f b k :=
  [/\ inc b Bnat, inc k Bnat, \1c <c b &
  [/\ fgraph f, domain f = Bint k &
  forall i, inc i (domain f) -> (Vg f i) <c b]].

Definition expansion_value f b :=
  card_sumb (domain f) (fun i=> (Vg f i) *c (b ^c i)).

Section Base_b_expansion.
Variables f g b k k': Set.
Variable Exp: expansion f b k.
Variable Expg: expansion g b (succ k').

Lemma expansion_prop0P i:
   (inc i (domain f)) <-> i <c k.
Proof. move: Exp => [_ kn _ [_ -> _]];exact: (BintP kn). Qed.

Lemma expansion_prop1 i:
  i <c k -> inc (Vg f i) Bnat.
Proof.
move: Exp => [bN kn _ [_ d v]] /expansion_prop0P idf.
move: (v _ idf) => [h _ ]; Bnat_tac.
Qed.

Lemma expansion_prop2:
   finite_int_fam (Lg (domain f) (fun i=> (Vg f i) *c (b ^c i))).
Proof.
move: Exp => [bB kB b2 [fgf df vf]].
hnf; rewrite /allf; bw; split.
  move=> i idf; bw; move /expansion_prop0P: idf => idf.
  apply: (BS_prod (expansion_prop1 idf) (BS_pow bB (BS_lt_int idf kB))).
by rewrite df; apply: finite_Bint.
Qed.

Lemma expansion_prop3: inc (expansion_value f b) Bnat.
Proof.
rewrite /expansion_value; apply: finite_sum_finite.
apply: expansion_prop2.
Qed.

Lemma expansion_prop4: cardinalp k' -> inc k' Bnat.
Proof. move: Expg => [_ kB' _ _] ck; apply: BS_nsucc => //. Qed.

Lemma expansion_prop5: cardinalp k' ->
  expansion (restr g (Bint k')) b k'.
Proof.
move => bk'; move: (expansion_prop4 bk')=> k'n.
move: (Bint_M k'n) => subi.
move: Expg => [bB kB b2 [fgf df vf]].
have dr: (domain (restr g (Bint k')) = Bint k') by bw; ue.
split;fprops; split; fprops.
rewrite dr; move=> i ic; bw; try ue.
by apply: vf; rewrite df; apply: subi.
Qed.

Lemma expansion_prop6: cardinalp k' -> inc (Vg g k') Bnat.
Proof.
move => bk'; move: (expansion_prop4 bk')=> k'n.
move: Expg => [bN kn _ [_ d v]].
have kd: (inc k' (domain g)) by rewrite d; apply:Bint_si.
move: (v _ kd)=> [h _]; Bnat_tac.
Qed.

Lemma expansion_prop7: cardinalp k' ->
  (expansion_value g b) =
   (expansion_value (restr g (Bint k')) b)
   +c (Vg g k' *c (b ^c k')).
Proof.
move => bk'; move: (expansion_prop4 bk')=> k'n.
pose h i := (Vg g i) *c (b ^c i).
have ->: (Vg g k') *c (b ^c k') = h k' by [].
rewrite /expansion_value.
move: (induction_on_sum h k'n); simpl.
have dg: domain g = (Bint (succ k'))
  by move: Expg=> [_ _ _ [_ dg _]].
rewrite -dg; set kk:= (Lg (domain g) h) ; move=> <-.
congr (card_sum _ +c (h k')).
move: (Bint_M k'n) => ii.
have fgg: fgraph g by move : Expg=> [_ _ _ []].
bw;apply: Lg_exten; move=> x xdf /=; bw; ue.
Qed.

End Base_b_expansion.

Lemma expansion_prop8 f b k x:
  let h:= Lg (Bint (succ k)) (fun i=> Yo (i=k) x (Vg f i)) in
 expansion f b k ->
   inc x Bnat -> x <c b ->
    (expansion h b (succ k) /\
      expansion_value h b =
      (expansion_value f b) +c ((b ^c k) *c x)).
Proof.
move=> h Expf xB xb.
move: Expf => [bB kB b2 [fgf df vf]].
have eg: (expansion h b (succ k)).
  red; rewrite /h; bw;split;fprops; split; fprops.
  move=> i idh; bw; Ytac ik => //; apply: vf.
  rewrite df; move: (Bint_pr4 kB)=> [p1 p2].
  move: idh; rewrite - p1; case /setU1_P => //.
have ck: cardinalp k by fprops.
rewrite (expansion_prop7 eg ck).
split; first by exact.
have ->:(restr h (Bint k)= f).
  rewrite /h; symmetry.
  move: (Bint_M kB) => si.
  apply: fgraph_exten=> //.
     fprops.
     bw; fprops.
  rewrite df; move=> y ydf /=; bw; fprops.
  by move: ydf => /(BintP kB) [_ yk]; Ytac0.
have -> //: (Vg h k *c (b ^c k) = (b ^c k) *c x).
by rewrite cprodC /h; bw;[ Ytac0 | apply: (Bint_si kB)].
Qed.

Lemma expansion_prop9 f b k: expansion f b k ->
   (expansion_value f b) <c (b ^c k).
Proof.
move=> Exp.
have kB: inc k Bnat by move: Exp => [bB kB _ _].
move: k kB f Exp.
apply: cardinal_c_induction.
  rewrite cpowx0.
  move=> g [bB _ b2 [fgf df _]].
  rewrite /expansion_value df Bint_co00 /card_sumb csum_trivial.
    apply: card_lt_01.
  bw.
move=> n nB pn g eg.
have cn: (cardinalp n) by fprops.
rewrite (expansion_prop7 eg cn).
move: (expansion_prop5 eg cn) => er.
move: (pn _ er).
move : eg => [bB _ b2 [fgf df vg]].
rewrite pow_succ //.
move: (expansion_prop3 er).
set (a0:= expansion_value (restr g (Bint n)) b).
set (b0:= b ^c n).
have p1: ((Vg g n) <c b).
  by apply: vg; rewrite df; apply:Bint_si.
have cB: inc (Vg g n) Bnat by move: p1 => [aux _]; Bnat_tac.
have b0B: inc b0 Bnat by rewrite /b0; apply: BS_pow.
set c0:= (Vg g n) *c b0.
move => a0B h.
have le1: (a0 +c c0) <c (b0 +c c0).
  apply: csum_Mlteq => //; rewrite /c0; fprops.
suff le2: (b0 +c c0) <=c (b0 *c b) by co_tac.
have cb: cardinalp b0 by fprops.
have ->: b0 +c c0 = b0 *c (succ (Vg g n)).
  rewrite (Bsucc_rw cB) cprod_sumDl (cprod1r cb) cprodC csumC //.
apply: cprod_Mlele; fprops.
by apply /(card_le_succ_ltP _ cB).
Qed.

Lemma expansion_prop10 f b k: cardinalp k ->
  expansion f b (succ k) ->
  card_division_prop (expansion_value f b) (b ^c k) (Vg f k)
  (expansion_value (restr f (Bint k)) b).
Proof.
move=> ck ie.
split.
  rewrite csumC cprodC.
  apply: expansion_prop7 =>//.
apply: expansion_prop9; apply: expansion_prop5 =>//.
Qed.

Lemma expansion_unique f g b k:
  expansion f b k -> expansion g b k ->
  expansion_value f b = expansion_value g b -> f = g.
Proof.
move=> ef eg sm.
have kB: inc k Bnat by move: eg => [_ kB _ _ ].
move: k kB f g sm ef eg.
apply: (cardinal_c_induction).
  rewrite /expansion Bint_co00.
  move=> f1 g1 sv [bB _ _ [fgf df _]] [_ _ _ [fgg dg _]].
  apply: fgraph_exten; [exact | exact | ue | ].
  by rewrite df;move=> x /in_set0.
move=> n nB pn f g sv ef eg.
have cn: cardinalp n by fprops.
move: (expansion_prop10 cn ef) => p1.
move: (expansion_prop10 cn eg) => p2.
rewrite sv in p1.
move: (expansion_prop5 ef cn) => er1.
move: (expansion_prop5 eg cn) => er2.
move:(expansion_prop3 eg) => egB.
have bB: inc b Bnat by move: ef => [bB _].
have cpB: inc (b ^c n) Bnat by fprops.
move: (expansion_prop6 ef cn) => q1B.
move: (expansion_prop6 eg cn) => q2B.
move: (expansion_prop3 er1) => r1B.
move: (expansion_prop3 er2) => r2B.
have bnz: (b ^c n <> card_zero).
  have [_ b0]: (\0c <c b).
    have aux: \0c <=c \1c by fprops.
    move: ef => [_ _ n1b _]; co_tac.
  by apply: cpow_nz => bz; case: b0.
move: (card_division_unique egB cpB q1B r1B q2B r2B bnz p1 p2)=> [pt r].
have aux: (restr f (Bint n) = restr g (Bint n)).
  apply: pn =>//.
move:ef eg=> [_ _ _ [fgf df _]] [_ _ _ [fgg dg _]].
apply: fgraph_exten; [ exact | exact | ue | ].
move=> x xdf.
case: (equal_or_not x n); first by move => ->.
move=> xn.
have xc: (inc x (Bint n)).
  move: xdf; rewrite df;
  move /(BintP(BS_succ nB)) /(card_lt_succ_leP nB) => h.
  by apply /(BintP nB); split.
have <-: (Vg (restr f (Bint n)) x = Vg f x).
  bw; rewrite df; apply: Bint_M =>//.
have <-: (Vg (restr g (Bint n)) x = Vg g x).
  bw; rewrite dg; apply: Bint_M =>//.
ue.
Qed.

Lemma expansion_prop11 f g b k: cardinalp k ->
  expansion f b (succ k) -> expansion g b (succ k) ->
  (Vg f k) <c (Vg g k) ->
  (expansion_value f b) <c (expansion_value g b).
Proof.
move=> ck ef eg ltk.
rewrite (expansion_prop7 ef ck) (expansion_prop7 eg ck).
move: (expansion_prop5 ef ck) => ef1.
move: (expansion_prop5 eg ck) => eg1.
move: (expansion_prop9 ef1).
move: (expansion_prop3 ef1).
move: (expansion_prop3 eg1).
set u:= expansion_value _ _; set v:= expansion_value _ _.
move=> uB vB vp.
move: (expansion_prop4 ef ck) => kB.
move: (expansion_prop6 ef ck) => fB.
move: (expansion_prop6 eg ck) => gB.
set (B:= card_pow b k).
have bB: inc b Bnat by move: ef => [h _].
have BB: (inc B Bnat) by rewrite /B; fprops.
have bb: (B <=c B) by rewrite /B;fprops.
apply: (@card_lt_leT _ (B +c ((Vg f k) *c B))).
  apply: csum_Mlteq; fprops.
apply: (@card_leT _ ((Vg g k) *c B)); last first.
  rewrite csumC; apply: csum_M0le; fprops.
move /(card_le_succ_ltP _ fB): ltk => ltk.
move: (cprod_Mlele ltk bb).
rewrite (Bsucc_rw fB) cprod_sumDr.
by rewrite (cprod1l (CS_Bnat BB)) csumC.
Qed.

Lemma expansion_restr1 f b k l:
  expansion f b k -> l <=c k ->
  expansion (restr f (Bint l)) b l.
Proof.
move=> [bB bK b2 [fgf df vg]] lk.
have lB: inc l Bnat by Bnat_tac.
split; fprops; split; fprops; bw => i idx; bw; apply: vg; rewrite df.
exact: (Bint_M1 bK lk).
Qed.

Lemma expansion_restr2 f b k l:
  expansion f b k -> l <=c k ->
  (forall i, l <=c i -> i <c k -> Vg f i = \0c) ->
  expansion_value (restr f (Bint l)) b = expansion_value f b.
Proof.
move=> ef lk p.
set g := fun i => expansion_value (restr f (Bint i)) b.
have <-: (g k = expansion_value f b).
  move: ef => [bB bK b2 [fgf df vg]].
  rewrite /g -df restr_to_domain //.
set r := fun i=> g l = g i.
change (r k).
have kB: inc k Bnat by move: ef => [bB bK _].
have lB: inc l Bnat by Bnat_tac.
have: inc k (interval_cc Bnat_order l k) by apply/ Bint_ccP1;fprops.
apply: (cardinal_c_induction3_v (r:=r) lB kB); first by trivial.
move=> i /(Bint_coP1 lB kB) [li ik]; rewrite /r => ->.
have iB: inc i Bnat by move: ik => [ik _]; Bnat_tac.
have ci: cardinalp i by fprops.
have ik': (succ i) <=c k by apply /card_le_succ_lt0P; fprops.
move:(expansion_restr1 ef ik').
set F := (restr f (Bint (succ i))).
move=> eF.
rewrite /g (expansion_prop7 eF ci).
set G := (restr F (Bint i)).
have si: sub (Bint (succ i)) (domain f).
  move: ef => [bB bK b2 [fgf df vg]].
  rewrite df; apply: Bint_M1;fprops.
have ->: (restr f (Bint i) = G).
 move: ef => [bB bK b2 [fgf df vg]].
 rewrite /G /F double_restr //.
 apply: Bint_M =>//.
have ->: (Vg F i = card_zero).
  move: ef => [bB bK b2 [fgf df vg]].
  rewrite /F; bw; try apply: p=>//.
  apply:Bint_si =>//.
rewrite cprodC cprod0r csum0r //.
rewrite /expansion_value/card_sumb/card_sum; fprops.
Qed.

Lemma expansion_prop12 f g b kf kg l n:
  n <=c kf -> n <=c kg -> l <c n ->
  (forall i, n <=c i -> i <c kf -> Vg f i = \0c) ->
  (forall i, n <=c i -> i <c kg -> Vg g i = \0c) ->
  (forall i, l <c i -> i <c n -> Vg f i = Vg g i) ->
  expansion f b kf -> expansion g b kg ->
  (Vg f l) <c (Vg g l) ->
  (expansion_value f b) <c (expansion_value g b).
Proof.
move=> nkf nkg ln pf pg pfg ef eg vl.
move: (expansion_restr1 ef nkf).
rewrite -(expansion_restr2 ef nkf pf).
move: (expansion_restr1 eg nkg).
rewrite -(expansion_restr2 eg nkg pg).
set F := (restr f (Bint n)).
set G := (restr g (Bint n)).
move=> eG eF; clear pf pg.
have kfB: inc kf Bnat by move: ef => [_ h _].
have nB: inc n Bnat by Bnat_tac.
have lB: inc l Bnat by move: ln => [ln _]; Bnat_tac.
have pFG: forall i, l <c i -> i <c n -> Vg F i = Vg G i.
  move=> i i1 i2; move: (pfg _ i1 i2).
  have ii: inc i (Bint n) by apply /BintP.
  move: ef eg => [_ _ _ [fgf df vf]] [_ kgB b2 [fgg dg vg]].
  rewrite /F/G; bw.
have vL: (Vg F l) <c (Vg G l).
  have ii: inc l (Bint n) by apply /BintP.
  move: ef eg => [_ _ _ [fgf df vf]] [_ kgB b2 [fgg dg vg]].
  rewrite /F/G; bw.
clear pfg vl ef eg.
set fi := fun i => expansion_value (restr F (Bint i)) b.
set gi := fun i => expansion_value (restr G (Bint i)) b.
have <-: (fi n = expansion_value F b).
  move: eF => [bB bK b2 [fgf df vg]].
  rewrite /fi -df restr_to_domain //.
have <-: (gi n = expansion_value G b).
  move: eG => [bB bK b2 [fgf df vg]].
  rewrite /gi -df restr_to_domain //.
pose r i := (fi i) <c (gi i).
change (r n).
have cl2: inc (succ l) Bnat by fprops.
have cl0: (succ l) <=c n by apply /card_le_succ_ltP.
have rz: (r (succ l)).
  rewrite /r /fi /gi.
  have cl: cardinalp l by fprops.
  have cl1: finite_c l by fprops.
  move: (expansion_restr1 eF cl0) => ef1.
  move: (expansion_restr1 eG cl0) => eg1.
  apply: (expansion_prop11 cl ef1 eg1).
  move: eF eG => [_ _ _ [fgf df vf]] [_ kgB b2 [fgg dg vg]].
  have il: inc l (Bint (succ l)).
    by apply:Bint_si.
  bw.
have: inc n (interval_cc Bnat_order (succ l) n).
   rewrite Bint_ccP1;fprops.
apply: (cardinal_c_induction3_v (r:=r) cl2 nB rz).
clear rz.
move=> i /(Bint_coP1 cl2 nB) [li ik] ri.
have iB: inc i Bnat by move: ik => [ik _]; Bnat_tac.
have ci: cardinalp i by fprops.
have ik': (succ i) <=c n by by apply /card_le_succ_ltP.
move:(expansion_restr1 eF ik').
move:(expansion_restr1 eG ik').
set f1 := (restr F (Bint (succ i))).
set g1 := (restr G (Bint (succ i))).
move=> ef1 eg1; move: ri.
rewrite /r /fi /gi (expansion_prop7 ef1 ci).
rewrite (expansion_prop7 eg1 ci).
set f2 := (restr f1 (Bint i)).
set g2 := (restr g1 (Bint i)).
have si: sub (Bint (succ i)) (domain F).
  move: eF => [bB bK b2 [fgf df vg]].
  rewrite df; apply: Bint_M1; fprops.
have sj: sub (Bint (succ i)) (domain G).
  move: eG => [bB bK b2 [fgf df vg]].
  rewrite df; apply: Bint_M1; fprops.
have ->: (restr F (Bint i) = f2).
  move: eF => [bB bK b2 [fgf df vg]].
  rewrite /f2 /f1 double_restr //.
  apply: Bint_M1; fprops.
have ->: (restr G (Bint i) = g2).
 move: eG => [bB bK b2 [fgf df vg]].
 rewrite /g2 /g1 double_restr //.
 by apply: Bint_M1;fprops.
have ->: (Vg f1 i = Vg g1 i).
  have ii:inc i (Bint (succ i)) by apply:Bint_si.
  move: eF => [bB bK b2 [fgf df vg]].
  move: eG => [_ _ _ [fgf' df' vg']].
  rewrite /f1 /g1; bw; try apply: pFG=>//.
  apply/card_le_succ_lt0P; fprops.
have isi: i <=c (succ i) by fprops.
move:(expansion_restr1 eg1 isi) => ef2.
move:(expansion_restr1 ef1 isi) => eg2.
apply: csum_Mlteq.
  have bB: inc b Bnat by move: ef1 => [ h _].
  apply: BS_prod; fprops.
  apply: (expansion_prop1 ef1); fprops.
apply: (expansion_prop3 eg2).
Qed.

Lemma expansion_prop13 f g b kf kg l:
  kf <=c l -> l <c kg ->
  expansion f b kf -> expansion g b kg ->
  Vg g l <> \0c ->
  (expansion_value f b) <c (expansion_value g b).
Proof.
move=> le1 le2 ef eg vnz.
apply: (@card_lt_leT _ (b ^c kf)).
apply: (expansion_prop9 ef).
move: eg => [bB bK b2 [fgf df vg]].
rewrite /expansion_value /card_sumb.
set F:= Lg _ _.
have fgF: fgraph F by rewrite /F;fprops.
have dF: domain F = Bint kg by rewrite /F -df; bw.
have alc: (forall x, inc x (domain F) -> cardinalp (Vg F x)).
  rewrite dF -df /F => x xdf; bw; fprops.
have ldf: inc l (domain F) by rewrite dF; apply /BintP.
set j:= singleton l.
have sj: sub j (domain F) by move => t /set1_P ->.
move: (csum_increasing1 alc sj).
rewrite (csum_trivial4 _ _ ) (card_card (alc _ ldf)).
suff: (b ^c kf) <=c (Vg F l) by move => p1 p2; co_tac.
have ldg: inc l (domain g) by rewrite df; apply /BintP.
rewrite /F; bw.
have bnz: b<> card_zero by move=>h; rewrite h in b2; case: (card_lt0 b2).
apply: (@card_leT _ (b ^c l)).
  apply: cpow_Mlele; fprops.
rewrite cprodC.
apply: cprod_M1le => //; rewrite /card_pow; fprops.
Qed.

Lemma expansion_prop14 f g b kf kg:
  expansion f b kf -> expansion g b kg ->
  (expansion_value f b) <c (expansion_value g b) ->
  (exists l, [/\ kf <=c l, l <c kg & Vg g l <> \0c])
 \/ (
  exists l n,
  [/\ n <=c kf, n <=c kg, l <c n &
  [/\ (forall i, n <=c i -> i <c kf -> Vg f i = \0c),
  (forall i, n <=c i -> i <c kg -> Vg g i = \0c) ,
  (forall i, l <c i -> i <c n -> Vg f i = Vg g i) &
   (Vg f l) <c (Vg g l)]]).
Proof.
move=> ef eg lt.
have kfb:inc kf Bnat by move: ef => [_ h _].
have kgb:inc kg Bnat by move: eg => [_ h _].
have [n [nf ng nfg]]: exists n,
   [/\ n <=c kf, n <=c kg & (n = kf \/ n = kg)].
  have k1:cardinalp kf by fprops.
  have k2:cardinalp kg by fprops.
  case: (card_le_to_ee k1 k2)=> aux; [exists kf | exists kg];split;fprops.
case: (p_or_not_p (forall i, n <=c i -> i <c kg -> Vg g i = \0c)); last first.
  move=> h.
  have [i [ni ik Vz]]: (exists i, [/\ n <=c i, i <c kg & Vg g i <> \0c]).
   ex_middle h'.
    case: h; move=> i i1 i2.
    case: (p_or_not_p (Vg g i = \0c)) =>// h''; case: h'; exists i => //.
  left; exists i; split => //.
  case: nfg; [by move=> <- | move=> nk; rewrite nk in ni; co_tac ].
move=> pB; right.
case: (p_or_not_p (forall i, n <=c i -> i <c kf -> Vg f i = \0c)); last first.
  move=> h.
  have [i [ni ik Vz]]: (exists i, [/\ n <=c i, i <c kf & Vg f i <> \0c]).
    ex_middle h'; case: h; move=> i i1 i2.
    case: (p_or_not_p (Vg f i = \0c)) =>// h''; case: h'; exists i; split => //.
  have fi: kg <=c i.
  case: nfg; [move=> nk; rewrite nk in ni; co_tac | by move=> <-].
  move: (expansion_prop13 fi ik eg ef Vz) =>[ br _].
  co_tac.
move=> pA.
have nB: inc n Bnat by case: nfg; move=> -> //.
have pC: exists2 l, l <c n& (Vg f l) <> (Vg g l).
  move: (expansion_restr2 ef nf pA) => hf.
  move: (expansion_restr2 eg ng pB) => hg.
  ex_middle bad.
  have eq: (restr f (Bint n) = restr g (Bint n)).
    move: ef eg => [bB bK b2 [fgf df vf]][_ _ _ [fgg dg vg]].
    have s1: sub (Bint n) (domain g).
      rewrite dg; apply: Bint_M1;fprops.
    have s2: sub (Bint n) (domain f).
      rewrite df; apply: Bint_M1;fprops.
    have drf: (domain (restr f (Bint n)) = Bint n) by bw.
    have drg: (domain (restr g (Bint n)) = Bint n) by bw.
    apply: fgraph_exten; fprops.
      ue.
    rewrite drf => x xdf; bw.
    ex_middle nx; case: bad; exists x => //.
    move: xdf => /(BintP nB) => //.
  move: lt;rewrite -hf -hg eq; move => [_ ne]; case: ne; apply: refl_equal.
have [l [lp ln Vl]]: exists l,
    [/\ (forall i : Set, l <c i -> i <c n -> Vg f i = Vg g i),
      l <c n & (Vg f l) <> (Vg g l)].
  set z:= Zo Bnat (fun l => l <c n /\ Vg f l <> Vg g l).
  have nz: nonempty z.
    move: pC => [l lp]; exists l; apply: Zo_i => //.
    move:lp => [lp _];Bnat_tac.
  have pa: (forall a, inc a z -> cardinalp a).
    move=> a /Zo_P [aB _ ]; fprops.
  move: (wordering_cardinal_le_pr pa) => [wor sr].
  move: (worder_total wor) => tor.
  have zc: sub z (Bint n).
    by move=> t /Zo_P [_ [p1 _]]; apply /BintP.
  have fsz: finite_set z.
   by apply: (sub_finite_set zc); apply: finite_Bint.
  have sw: sub z (substrate (graph_on cardinal_le z)) by rewrite sr; fprops.
  move: (finite_subset_torder_greatest tor fsz sw nz)=> [l []].
  move: wor => [or _].
  aw; move=> lz lp; exists l.
  move: (lz); move => /Zo_P [lB [ln Vl]]; split => //.
  move=> i li lin.
  have iB: inc i Bnat by move: lin => [lin _ ]; Bnat_tac.
  case: (equal_or_not (Vg f i) (Vg g i)) => // h.
  have iz: inc i z by apply: Zo_i => //.
  move: (iorder_gle1 (lp _ iz)) => /graph_on_P1 [_ _ il]; co_tac.
exists l; exists n; split => //.
  have p1: cardinalp (Vg f l).
    move: ef =>[bB bK b2 [fgf df vf]].
    have ldf: (inc l (domain f)) by rewrite df; apply /BintP => //; co_tac.
    by move: (vf _ ldf)=> [[res _] _ ].
  have p2: cardinalp (Vg g l).
    move: eg =>[bB bK b2 [fgf df vf]].
    have ldf: (inc l (domain g)) by rewrite df;apply /BintP => //; co_tac.
    by move: (vf _ ldf)=> [[res _] _ ].
  case: (card_le_to_el p2 p1) => //.
  move=> h.
  have p3: (Vg g l) <c (Vg f l) by split => //; apply: nesym.
  have lp' : forall i, l <c i -> i <c n -> Vg g i = Vg f i.
    by move=> i i1 i2; symmetry;move: (lp _ i1 i2).
  move: (expansion_prop12 ng nf ln pB pA lp' eg ef p3) => [p4 _].
  co_tac.
Qed.

Lemma expansion_exists1 a b k:
  inc b Bnat -> \1c <c b -> inc k Bnat ->
  inc a Bnat -> a <c (b ^c k) ->
  exists2 f, expansion f b k & expansion_value f b = a.
Proof.
move=> bB b1 kB; move: k kB a.
apply: cardinal_c_induction.
  rewrite cpowx0 => c cB c1.
  exists (Lg emptyset (fun _ => card_zero)) => //;bw.
    split;fprops; split; fprops.
      by bw; rewrite - Bint_co00.
    by bw; move=> i /in_set0.
  rewrite /expansion_value/card_sumb; bw; rewrite csum_trivial; bw.
  move: c1; rewrite - succ_zero; move / (card_lt_succ_leP BS0) => aux.
  by symmetry; apply: card_le0.
move=> n nB pn c cB cp.
set (b0:= b ^c n).
have b0B: (inc b0 Bnat) by rewrite /b0; fprops.
have Bz: (b0 <> card_zero).
  have aux:(\0c <c b) by move: card_lt_01 => aux'; co_tac.
  have bnz: b<> card_zero by move: aux => [_]; apply: nesym.
  apply: (cpow_nz bnz).
move: (card_division_exists cB b0B Bz) => [q [r [qB rB [aux lt]]]].
rewrite /b0 in lt.
move: (pn _ rB lt) => [f ise ev].
have p1: (b0 *c q) <c (b0 *c b).
  have p2: ((b0 *c q) <=c c).
    rewrite aux; apply: csum_M0le; fprops.
  have p3: (inc (b0 *c q) Bnat) by fprops.
  rewrite /b0 - pow_succ -/b0; fprops.
  co_tac.
move: (cprod_lt_simplifiable b0B qB bB Bz p1) => qb.
move: (expansion_prop8 ise qB qb).
set F:= (Lg _ _).
move=> [s1 s2]; exists F => //.
rewrite s2 ev aux csumC /b0; apply: refl_equal.
Qed.

Lemma expansion_exists a b: inc a Bnat -> inc b Bnat ->
  \1c <c b -> exists k f,
    (expansion f b k /\ expansion_value f b = a).
Proof.
move=> aB bB b1; exists a.
have [f pa pb]:exists2 f, expansion f b a & expansion_value f b = a.
  by apply: expansion_exists1 => //; apply: cpow_M1lt; fprops.
by exists f.
Qed.

Definition eqmod a b B:= a %%c B = b %%c B.

Section ModuloProps.
Variable B: Set.
Hypothesis Bn: inc B Bnat.
Hypothesis Bnz: B <> \0c.

Lemma crem_prop a b: inc a Bnat -> inc b Bnat ->
  eqmod ((B *c a) +c b) b B.
Proof.
move=> aB bB; rewrite /eqmod.
move: (card_division bB Bn Bnz).
set q := b %/c B; set r := b %%c B.
move=> [q1B r1B [aeq r1p]].
rewrite aeq csumA - cprod_sumDl.
set q2:= (a +c q).
have q2B: inc q2 Bnat by rewrite /q2; apply: BS_sum.
set A:= ((B *c q2) +cr).
have dp: (card_division_prop A B q2 r) by split;[apply: refl_equal | done].
move: (cquorem_pr (BS_sum (BS_prod Bn q2B) r1B) Bn q2B r1B dp).
by move=> [_ h]; symmetry.
Qed.

Lemma crem_sum a b: inc a Bnat -> inc b Bnat ->
  eqmod (a +c b) ((a %%c B) +c (b %%c B)) B.
Proof.
move=> aB bB.
move: (card_division aB Bn Bnz) (card_division bB Bn Bnz).
rewrite /card_division_prop.
set q1:= a %/cB; set q2:= b %/c B; set r1:= a %%c B; set r2:= b %%c B.
move=> [q1B r1B [aeq r1p]][q2B r2B [beq r2p]].
rewrite aeq beq.
set t := _ +c _.
have ->: t= (B *c (q1 +c q2)) +c (r1 +c r2).
  rewrite cprod_sumDl csumA.
  set (s1:= B *c q1); set (s2:= B *c q2).
  by rewrite /t (csum_permute24) -/s1 -/s2 csumA.
apply:(crem_prop (BS_sum q1B q2B) (BS_sum r1B r2B)).
Qed.

Lemma crem_mult a b: inc a Bnat -> inc b Bnat ->
  eqmod (a *c b) ((a %%c B) *c (b %%c B)) B.
Proof.
move=> aB bB.
move: (card_division aB Bn Bnz) (card_division bB Bn Bnz).
set q1:= a %/cB; set q2:= b %/c B; set r1:= a %%c B; set r2:= b %%c B.
rewrite /card_division_prop.
move=> [q1B r1B [aeq r1p]][q2B r2B [beq r2p]].
rewrite aeq beq.
rewrite cprod_sumDl(cprodC B q2) cprodA (cprodC _ B).
set v := ((B *c q1) +c r1) *c q2.
rewrite cprod_sumDr - cprodA csumA - cprod_sumDl.
apply: crem_prop ; [apply: BS_sum | ]; apply: BS_prod => //; ue.
Qed.

Lemma eqmod_plus a b a' b': inc a Bnat -> inc b Bnat ->
  inc a' Bnat -> inc b' Bnat ->
  eqmod a a' B -> eqmod b b' B -> eqmod (a +c b) (a' +c b') B.
Proof.
move=> aB bB a'B b'B; rewrite /eqmod => e1 e2.
rewrite (crem_sum aB bB) e1 e2 (crem_sum a'B b'B); reflexivity.
Qed.

Lemma eqmod_mult a b a' b': inc a Bnat -> inc b Bnat ->
  inc a' Bnat -> inc b' Bnat ->
  eqmod a a' B -> eqmod b b' B -> eqmod (a *c b) (a' *c b') B.
Proof.
move=> aB bB a'B b'B e1 e2.
rewrite /eqmod in e1 e2 |- *.
rewrite (crem_mult aB bB) (crem_mult a'B b'B) e1 e2; reflexivity.
Qed.

Lemma eqmod_rem a: inc a Bnat -> eqmod a (a %%c B) B.
Proof.
move=> aB.
rewrite {1} (cdiv_pr aB Bn); apply: crem_prop; fprops.
Qed.

Lemma eqmod_succ a a': inc a Bnat -> inc a' Bnat ->
  eqmod a a' B -> eqmod (succ a) (succ a') B.
Proof.
move=> aB a'B e1.
rewrite !card_succ_pr4; fprops; apply: eqmod_plus => //; fprops.
Qed.

Lemma eqmod_pow1 a n: inc a Bnat -> inc n Bnat ->
  eqmod a \1c B -> eqmod (a ^c n) \1c B.
Proof.
move=> aB nB h; move: n nB.
apply: cardinal_c_induction; first by rewrite cpowx0.
move=> n nB h1.
move: (eqmod_mult (BS_pow aB nB) aB BS1 BS1 h1 h).
rewrite (pow_succ _ nB) (cprod1r); fprops.
Qed.

Lemma eqmod_pow2 a b n: inc a Bnat -> inc b Bnat -> inc n Bnat ->
  eqmod a \1c B -> eqmod (b *c (a ^c n)) b B.
Proof.
move=> aB bB nB h.
move: (eqmod_pow1 aB nB h) => h2.
have aux: eqmod b b B by [].
move: (eqmod_mult bB (BS_pow aB nB) bB BS1 aux h2).
rewrite cprod1r; fprops.
Qed.

Lemma eqmod_pow3 f b k: expansion f b k ->
   eqmod b \1c B -> eqmod (expansion_value f b) (card_sum f) B.
Proof.
move=> ep b1.
have kB: inc k Bnat by move: ep => [bB kB _].
move: k kB f ep.
set (p:= fun n => forall f, expansion f b n ->
  eqmod (expansion_value f b) (card_sum f) B).
apply: (cardinal_c_induction (r:=p)).
  move=> g [bB _ b2 [fgf df _]].
  have dge: domain g = emptyset by move: df; rewrite Bint_co00.
  rewrite /expansion_value/card_sumb dge !csum_trivial //; bw.
move=> n nB pn g eg.
have cn: (cardinalp n) by fprops.
rewrite (expansion_prop7 eg cn).
move: (expansion_prop5 eg cn) => er.
move: (eg) => [bB _ _ [fgg dg _]].
move: (BS_succ nB) => snB.
have si: sub (Bint n) (domain g).
  rewrite dg; apply: (Bint_M nB).
have ->: (card_sum g =
   (card_sum (restr g (Bint n))) +c (Vg g n)).
  pose h w := \0c +c (Vg g w).
  have hp: forall x, inc x (domain g) -> h x = Vg g x.
    move=> x; rewrite dg; move /(BintP snB) => p1.
    move: (expansion_prop1 eg p1) => p2.
    rewrite /h; aw; fprops.
  move: (induction_on_sum h nB); simpl.
  have ->: h n = Vg g n by apply: hp; rewrite dg; apply:Bint_si.
  rewrite /card_sumb.
  have ->: (Lg (Bint (succ n)) h = g).
    apply: fgraph_exten; fprops; first by symmetry;bw.
    bw; move=> x xd /=; bw; apply: hp; ue.
  have ->: (Lg (Bint n) h = (restr g (Bint n))).
    apply: fgraph_exten; fprops.
      by bw; rewrite (restr_d fgg si).
    bw; move=> x xb /=; bw; apply: (hp _ (si _ xb)).
  by move => ->.
have p1: inc (Vg g n) Bnat by apply: (expansion_prop1 eg (card_lt_succ nB)).
have p2: inc ((Vg g n) *c (b ^c n)) Bnat.
   apply: (BS_prod p1 (BS_pow bB nB)).
have p3: inc (card_sum (restr g (Bint n))) Bnat.
  apply: finite_sum_finite_aux; last by exact.
  split => //.
    move=> i; rewrite dg; move /(BintP snB).
    apply: (expansion_prop1 eg).
  by rewrite dg; apply: finite_Bint.
apply: (eqmod_plus (expansion_prop3 er) p2 p3 p1 (pn _ er)).
apply: (eqmod_pow2 bB p1 nB b1).
Qed.

End ModuloProps.

Definition card_five := succ card_four.
Definition card_ten := card_five +c card_five.
Notation "\10c" := card_ten.

Lemma BS5 : inc card_five Bnat.
Proof. apply: (BS_succ BS4). Qed.

Lemma BS10 : inc \10c Bnat.
Proof. apply: (BS_sum BS5 BS5). Qed.

Lemma card_plus_3_2: \3c +c \2c = card_five.
Proof.
rewrite /card_five (Bsucc_rw BS4) /card_four (Bsucc_rw BS3).
by rewrite - csumA card_two_pr.
Qed.

Lemma card_mult_3_3: \10c = succ (\3c *c \3c).
Proof.
have aux: forall n, cardinalp n -> (n +c n) +c n = n *c \3c.
  move=> n cn; rewrite /card_three (Bsucc_rw BS2).
  rewrite cprod_sumDl.
  by rewrite (cprod1r cn) cprodC two_times_n.
rewrite / \10c - card_plus_3_2 - csum_permute24.
set t:= (\3c +c \3c).
rewrite csumA -{2} succ_one (csum_via_succ _ BS1) - csumA - (Bsucc_rw BS2).
congr (succ _);apply: aux; apply: (CS_Bnat BS3).
Qed.

Lemma card_mult_10_3: eqmod \10c \1c \3c.
Proof.
rewrite card_mult_3_3 (Bsucc_rw (BS_prod BS3 BS3)).
apply: (crem_prop BS3) BS3 BS1.
rewrite /card_three; apply: succ_nz.
Qed.

Definition expansion_ten f k :=
  [/\ inc k Bnat, fgraph f, domain f = Bint k &
  forall i, inc i (domain f) -> (Vg f i) <c \10c].

Lemma divisibiliy_by_three f k: expansion_ten f k ->
  let g:= (Lg (domain f) (fun i=> (Vg f i) *c (\10c ^c i))) in
  eqmod (card_sum g) (card_sum f) \3c.
Proof.
move=> [p1 p2 p3 p4].
have C30: card_three <> card_zero by rewrite /card_three; apply: succ_nz.
have ep: expansion f \10c k.
  split => //; first by apply: BS10.
  move: (BS_prod BS3 BS3) => i9B.
  rewrite card_mult_3_3; apply /(card_lt_succ_leP i9B).
  apply: card_ge1; first by fprops.
  apply: (cprod2_nz C30 C30).
exact (eqmod_pow3 BS3 C30 ep card_mult_10_3).
Qed.

Even and odd integers

Definition even_int n := inc n Bnat /\ card_rem n \2c = \0c.
Definition odd_int n := inc n Bnat /\ ~ (even_int n).

Lemma even_double n: inc n Bnat -> even_int (\2c *c n).
Proof. move => h; split; fprops; exact: (proj33 (cdivides_pr1 h BS2)). Qed.

Lemma half_even n: even_int n -> n = \2c *c (n %/c \2c).
Proof. move => [nB pb]; move: (cdiv_pr nB BS2); rewrite pb; aw; fprops. Qed.

Lemma even_odd_succ n:
  (even_int n -> odd_int (succ n)) /\ (odd_int n -> even_int (succ n)).
Proof.
move: (card2_nz) => n2z.
have aux: forall p m, inc p Bnat -> inc m Bnat ->
  succ (\2c *c p) <> (\2c *c m).
  move=> p m pB mB bad; move: (CS_Bnat pB) => cp.
  have le2:(\2c <=c \2c) by fprops.
  have p1: forall a, inc a Bnat -> (succ a) <=c a -> False.
     move => a ab; move: (card_lt_succ ab) => p1 p2; co_tac.
  case: (card_le_to_el (CS_Bnat mB) cp) => pm.
     move: (cprod_Mlele le2 pm); rewrite - bad; apply:p1; fprops.
  have pa: cardinalp (\2c *c p +c \1c) by fprops.
  have pb: cardinalp (\2c *c p) by fprops.
  move: pm => /(card_le_succ_lt0P cp mB) mp.
  move: (cprod_Mlele le2 mp); rewrite -bad (card_succ_pr4 cp) cprod_sumDl.
  rewrite (cprod1r CS2) - {2} card_two_pr csumA -(card_succ_pr4 pa).
  rewrite -(card_succ_pr4 pb); apply: p1; fprops.
rewrite /odd_int /even_int.
split.
  move=> [nB rz].
  have snB: (inc (succ n) Bnat) by fprops.
  split => //; move => [_ h].
  move:(card_division snB BS2 n2z).
  move:(card_division nB BS2 n2z).
  rewrite rz h /card_division_prop; aw; fprops.
  move=> [q1n _ [np _]] [q2n _ [np' _]].
  by rewrite {1} np in np'; case: (aux _ _ q1n q2n).
move=> [nB h].
move: (card_division nB BS2 n2z)=> [qB rB [nv r2]].
case: (card_lt2 r2) => h1; first by case: h;split => //.
rewrite h1 in nv; clear h1 r2 rB.
have snB: (inc (succ n) Bnat) by fprops.
split => //.
move: (card_division snB BS2 n2z) => [q2B rB [nv2 r2]].
case: (card_lt2 r2) => // h1.
have cn: cardinalp n by fprops.
move: nv2; rewrite h1 {1} card_succ_pr4 //.
set s:= _ *c _ => nv2.
have cs: cardinalp s by rewrite /s; fprops.
move: nv; rewrite - card_succ_pr4; last by fprops.
rewrite {1} (succ_injective cn cs nv2) /s => aux1.
by case: (aux _ _ qB q2B).
Qed.

Lemma even_odd_pred n: inc n Bnat ->
   ( (even_int (succ n) -> odd_int n)
    /\ (odd_int (succ n) -> even_int n)).
Proof.
move: (even_odd_succ n) => [pa pb] nB.
case: (p_or_not_p (even_int n)) => evn; split => //.
  by move => es; move: (pa evn); move => [].
by move => [ta tb]; case: tb; apply pb; split.
Qed.

Lemma even_odd_sum x y:
  [/\ (odd_int x -> odd_int y -> even_int (x +c y)),
    (even_int x -> odd_int y -> odd_int (x +c y)) &
    (even_int x -> even_int y -> even_int (x +c y))].
Proof.
have aux: forall a b, (even_int a -> even_int b -> even_int (a +c b)).
  move => a b [aB ai][bB bi]; split; first by fprops.
  have d1: (\2c %|c a) by split;fprops.
  have d2: (\2c %|c b) by split;fprops.
  by move: (cdivides_and_sum d1 d2) => [[_ _ r2] _].
have aux2: forall a b, (even_int a -> odd_int b -> odd_int (a +c b)).
  move => a b ea ob.
  have bB: inc b Bnat by move: ob =>[yb _].
  have sB: inc (a +c b) Bnat by move: ea => [xb _]; fprops.
  move:(proj1 (even_odd_pred sB)); apply.
  rewrite - csum_via_succ //; apply aux => //.
  by apply:(proj2 (even_odd_succ b)).
split;fprops.
move => ox oy.
have yB: inc y Bnat by move: oy =>[yb _].
have sB: inc (x +c y) Bnat by move: ox => [xb _]; fprops.
move:(proj2 (even_odd_pred sB)); apply.
rewrite - csum_via_succ //; rewrite csumC; apply: aux2 => //.
by apply:(proj2 (even_odd_succ y)).
Qed.

Lemma even_zero: even_int \0c.
Proof. move: (cdivision_of_zero BS2) => [[_ _ res] _]; split;fprops. Qed.

Lemma odd_one: odd_int \1c.
Proof. by move: (proj1 (even_odd_succ \0c) even_zero); rewrite succ_zero. Qed.

Lemma even_two: even_int \2c.
Proof. by move: (proj2 (even_odd_succ \1c) odd_one); rewrite succ_one. Qed.

EIII-5-8 Combinatorial analysis



Lemma segment_Bnat_order1 n: inc n Bnat -> segment Bnat_order n = n.
Proof.
move=> nB; rewrite (segment_Bnat_order nB).
set_extens t.
  move/(BintP nB) => h.
  by move: (ordinal_cardinal_lt h); move/ord_ltP0 => [_ _].
move => tn.
move: (CS_Bnat(ordinal_transitive OS_omega nB tn)) => ct.
move: (CS_Bnat nB) => cn; move: (ct) (cn) => [ot _] [on _].
apply/(BintP nB); rewrite -(card_card ct).
by apply /(ordinal_cardinal_le2P cn ot) /(ord_ltP on).
Qed.

Definition induction_defined0 (h: fterm2) (a: Set) :=
  transfinite_defined Bnat_order
  (fun u => Yo(source u = \0c) a
     (h (cpred (source u))(Vf u (cpred (source u))))).

Definition induction_defined (s: fterm) (a: Set) :=
  transfinite_defined Bnat_order
  (fun u => Yo(source u = \0c) a (s (Vf u (cpred (source u))))).

Lemma induction_defined_pr0 h a (f := induction_defined0 h a):
     [/\ source f = Bnat, surjection f, Vf f \0c = a &
     forall n, inc n Bnat -> Vf f (succ n) = h n (Vf f n)].
Proof.
rewrite /f /induction_defined0.
set p := (fun u : Set => _).
move: Bnat_order_wor => [wo sr].
move: (transfinite_defined_pr p wo).
set g := (transfinite_defined Bnat_order p).
move=> [pa pb pc].
have p1: forall a, inc a Bnat ->
   source (restriction1 f (segment Bnat_order a))= a.
  move=> b bB; rewrite /restriction1; aw.
  by rewrite segment_Bnat_order1.
rewrite sr in pb pc; split => //.
  by rewrite (pc _ BS0) /restriction_to_segment /p (p1 _ BS0); Ytac0.
move=> n nB; move:(BS_succ nB) => snB;rewrite (pc _ snB) /p (p1 _ snB).
rewrite (Y_false (@succ_nz n)) (cpred_pr2 nB).
congr (h n _); rewrite restriction1_V //; first by fct_tac.
  rewrite segment_Bnat_order // ? pb.
  apply: Bint_S1.
by rewrite (segment_Bnat_order snB); apply: Bint_si.
Qed.

Lemma induction_defined_pr s a (f := induction_defined s a):
    [/\ source f = Bnat, surjection f, Vf f \0c = a &
     forall n, inc n Bnat -> Vf f (succ n) = s (Vf f n)].
Proof.
rewrite /f /induction_defined.
set p := (fun u : Set => _).
move: Bnat_order_wor => [wo sr].
move: (transfinite_defined_pr p wo).
set g := (transfinite_defined Bnat_order p).
move=> [pa pb pc].
have p1: forall a, inc a Bnat ->
   source (restriction1 f (segment Bnat_order a))= a.
  move=> b bB; rewrite /restriction1; aw.
  by rewrite segment_Bnat_order1.
rewrite sr in pb pc; split => //.
  by rewrite (pc _ BS0) /restriction_to_segment /p (p1 _ BS0); Ytac0.
move=> n nB; move:(BS_succ nB) => snB;rewrite (pc _ snB) /p (p1 _ snB).
rewrite (Y_false (@succ_nz n)) (cpred_pr2 nB).
congr (s _); rewrite restriction1_V //; first by fct_tac.
  rewrite segment_Bnat_order // ? pb.
  apply: Bint_S1.
by rewrite (segment_Bnat_order snB); apply: Bint_si.
Qed.

Lemma integer_induction0 h a: exists! f,
  [/\ source f = Bnat, surjection f,
    Vf f \0c = a &
    forall n, inc n Bnat -> Vf f (succ n) = h n (Vf f n)].
Proof.
exists (induction_defined0 h a); split.
  apply: (induction_defined_pr0).
move:(induction_defined_pr0 h a) => [sy sjy y0 ys] x [sx sjx x0 xs].
apply: function_exten4=>//; first by ue.
rewrite sy; apply: cardinal_c_induction; first by ue.
by move=> n nB eq; rewrite (xs _ nB) (ys _ nB) eq.
Qed.

Lemma integer_induction s a: exists! f,
  [/\ source f = Bnat, surjection f, Vf f \0c = a &
  forall n, inc n Bnat -> Vf f (succ n) = s (Vf f n)].
Proof.
set (h:= fun _ x:Set => s x).
move: (integer_induction0 h a) => //.
Qed.

Definition induction_term s a := Vf (induction_defined0 s a).

Lemma induction_term0 s a:
  induction_term s a \0c = a.
Proof.
move: (induction_defined_pr0 s a)=> [sf sjf w0 ws].
rewrite /induction_term //.
Qed.

Lemma induction_terms s a n:
  inc n Bnat ->
  induction_term s a (succ n) = s n (induction_term s a n).
Proof.
move: (induction_defined_pr0 s a)=> [sf sjf w0 ws] nB.
rewrite /induction_term ws //.
Qed.

Theorem shepherd_principle f c: function f ->
  (forall x, inc x (target f) -> cardinal (inv_image_by_fun f (singleton x))=c)
  -> cardinal (source f) = (cardinal (target f)) *c c.
Proof.
move=> ff cc.
set (pa := Lg (target f) (fun z=> (inv_image_by_fun f (singleton z)))).
have up: (unionb pa = (source f)).
  set_extens x.
    rewrite /pa; move /setUb_P; bw; move => [y ytf]; bw.
    move /iim_fun_P => [u /set1_P -> Jg];Wtac.
  move => xsf; move: (Vf_target ff xsf)=> Wt.
  apply /setUb_P; exists (Vf f x); rewrite /pa; bw => //.
  by apply: iim_fun_set1_i.
have md: (mutually_disjoint pa).
  apply: mutually_disjoint_prop.
  rewrite/pa /inv_image_by_fun; bw=> i j y it jt; bw.
  move => sa sb.
  by rewrite (iim_fun_set1_hi ff sa) (iim_fun_set1_hi ff sb).
have fgp: (fgraph pa) by rewrite /pa; fprops.
move: (csum_pr pa); rewrite /card_sumb.
set f' := Lg _ _.
have ->: f' =cst_graph (domain pa) c.
  apply: Lg_exten; rewrite /pa; bw; move => x xtf /=; bw; apply: cc=>//.
rewrite csum_of_same.
have ->:c *c (domain pa) = (cardinal (target f)) *c c.
  rewrite cprodC /pa; bw.
  apply: cprod2_pr2; fprops; symmetry;apply: card_card; fprops.
move => <-.
rewrite -up; apply /card_eqP.
apply: equipotent_disjointU; fprops.
rewrite /disjointU_fam; split;fprops; bw.
move=> i id; bw; fprops.
Qed.

Definition factorial n :=
  card_prod (Lg (Bint n) succ).

Lemma factorial_succ n: inc n Bnat ->
  factorial (succ n) = (factorial n) *c (succ n).
Proof.
by move=> nB; rewrite (induction_on_prod succ nB).
Qed.

Lemma factorial0: factorial \0c = \1c.
Proof.
rewrite /factorial Bint_co00 cprod_trivial;fprops;bw.
Qed.

Lemma factorial1: factorial \1c = \1c.
Proof.
move: BS0 => zb.
rewrite - succ_zero factorial_succ // factorial0; aw; apply: CS_succ.
Qed.

Lemma factorial2: factorial \2c = \2c.
Proof.
rewrite - succ_one.
rewrite (factorial_succ BS1) factorial1 succ_one;aw; fprops.
Qed.

Lemma factorial_nz n: inc n Bnat -> factorial n <> \0c.
Proof.
move: n;apply: cardinal_c_induction.
  rewrite factorial0; exact: card1_nz.
move=> m mB u; rewrite (factorial_succ mB).
apply: cprod2_nz =>//; apply: succ_nz.
Qed.

Lemma BS_factorial n: inc n Bnat -> inc (factorial n) Bnat.
Proof.
move=> nB.
apply: (cardinal_c_induction (r:=fun n=> inc (factorial n) Bnat)) =>//.
  rewrite factorial0; fprops.
move=> m mB u; rewrite (factorial_succ mB); fprops.
Qed.

Hint Resolve factorial_nz: fprops.

Lemma factorial_prop f: f \0c = \1c ->
  (forall n, inc n Bnat -> f (succ n) = (f n) *c (succ n)) ->
  forall x, inc x Bnat -> f x = factorial x.
Proof.
move=> fz fp; apply: cardinal_c_induction.
  rewrite factorial0 //.
move=> m mB u; rewrite (factorial_succ mB) (fp _ mB) u // .
Qed.

Lemma factorial_induction n: inc n Bnat ->
 factorial n = induction_term (fun a b => b *c(succ a)) \1c n.
Proof.
move: n;apply: cardinal_c_induction.
  by rewrite factorial0 induction_term0.
by move=> m mB h; rewrite (factorial_succ mB) (induction_terms _ _ mB) h.
Qed.

Lemma quotient_of_factorials a b:
  inc a Bnat -> inc b Bnat -> b <=c a ->
  (factorial b) %|c (factorial a).
Proof.
move=> aB bB ab; rewrite -(cdiff_rpr ab).
move: (BS_diff b aB).
set (c := a -c b);rewrite csumC.
generalize c; apply: cardinal_c_induction.
  rewrite (bsum0r bB).
  apply: cdivides_itself.
   apply: BS_factorial =>//.
   apply: factorial_nz =>//.
move => n nB.
rewrite (csum_via_succ _ nB).
have p1: inc (b +c n) Bnat by fprops.
rewrite factorial_succ //;apply: cdivides_trans2; fprops.
Qed.

Lemma quotient_of_factorials1 a b:
  inc a Bnat -> inc b Bnat -> b <=c a ->
  (factorial (a -c b)) %|c (factorial a).
Proof.
move=> aB bB leab; apply: (quotient_of_factorials aB).
  fprops.
apply: cdiff_le_symmetry=>//.
Qed.

Lemma factorial_monotone a b: inc b Bnat -> a <=c b ->
     factorial a <=c factorial b.
Proof.
move => bB leab.
move:(quotient_of_factorials bB (BS_le_int leab bB) leab) => [p1 p2 p3].
move:(cdiv_pr p1 p2); rewrite p3 (csum0r); last by fprops.
set q := _ %/c _.
case (equal_or_not q \0c) => qz.
   by move:(factorial_nz bB); rewrite qz cprod0r.
move => ->; apply: (cprod_M1le (CS_Bnat p2) qz).
Qed.

Definition number_of_injections b a :=
  (factorial a) %/c (factorial (a -c b)).

Lemma number_of_injections_pr a b:
  inc a Bnat -> inc b Bnat -> b <=c a ->
  (number_of_injections b a) *c (factorial (a -c b)) = factorial a.
Proof.
rewrite/number_of_injections.
move=> aB bB leba; rewrite cprodC.
symmetry;apply: cdivides_pr3=>//.
by apply: quotient_of_factorials1.
Qed.

Lemma number_of_injections_int a b:
  inc a Bnat -> inc b Bnat ->
  inc (number_of_injections b a) Bnat.
Proof.
rewrite/number_of_injections => aB bB.
apply: (BS_quo (BS_factorial aB) (BS_factorial (BS_diff b aB))).
Qed.

Lemma number_of_injections_base a: inc a Bnat ->
  number_of_injections \0c a = \1c.
Proof.
rewrite /number_of_injections=> aB.
rewrite cdiff_n_0=> //.
apply: (cquo_itself (BS_factorial aB) (factorial_nz aB)).
Qed.

Lemma number_of_injections_rec a b:
  inc a Bnat -> inc b Bnat -> b <c a ->
  (number_of_injections b a) *c (a -c b) =
  number_of_injections (succ b) a.
Proof.
move=> aB bB ltab.
have leab: b <=c a by move: ltab => [le _].
move: (number_of_injections_pr aB bB leab).
set A:= number_of_injections b a.
have sB: inc (succ b) Bnat by fprops.
move /(card_le_succ_ltP _ bB): ltab => ltab.
rewrite - (number_of_injections_pr aB sB ltab).
set B:= number_of_injections (succ b) a.
have sb: inc (a -c (succ b)) Bnat by fprops.
rewrite (csucc_diff aB bB ltab).
rewrite factorial_succ; last by fprops.
set w := (succ (a -c (succ b))).
have wB: inc w Bnat by rewrite /w; fprops.
set D:= factorial (a -c (succ b)).
rewrite (cprodC D _) cprodA.
apply: cprod_simplifiable_right.
- rewrite /D; apply: BS_factorial =>//.
- apply: BS_prod.
    rewrite /A; apply: number_of_injections_int =>//.
    exact.
- rewrite /B; apply: number_of_injections_int =>//.
- by apply: factorial_nz.
Qed.

Definition injections E F :=
  Zo (functions E F)(injection).

Lemma number_of_injections_prop E F:
  finite_set F ->
  cardinal E <=c cardinal F ->
  cardinal (injections E F) =
    number_of_injections (cardinal E) (cardinal F).
Proof.
move=> fsF lce.
set (m:= cardinal F).
have fse: finite_set E by red; red in fsF; Bnat_tac.
move: lce.
have mB: inc m Bnat by apply /BnatP; rewrite /m; red in fsF.
pose s E := (cardinal E) <=c m ->
   cardinal (injections E F) = number_of_injections (cardinal E) m.
apply: (finite_set_induction0 (s:=s)) =>//.
  rewrite /s cardinal_set0 number_of_injections_base //.
  move=> _.
  move: (empty_function_tg_function F); set f:= empty_function_tg F;
  move => [pa pb pc].
  have injf: injection f.
    split => //; rewrite /f pb => x y; case; case.
  have : (inc f (functions (source f) (target f))) by apply /fun_set_P.
  rewrite pb pc => aux.
  have ->: (injections emptyset F = singleton f).
    apply : set1_pr; first by apply:Zo_i.
    by move => z /Zo_S vs; rewrite (fun_set_small_source vs aux).
  by rewrite cardinal_set1.
clear fse E.
move=> E a sE naE; rewrite /s.
rewrite (card_succ_pr naE).
set (n := cardinal E).
move=> lem.
have snB: inc (succ n) Bnat by Bnat_tac.
have nB: inc n Bnat by apply: BS_nsucc; rewrite /n; fprops.
have ltnm: n <c m by apply /card_le_succ_ltP.
rewrite -(number_of_injections_rec mB nB ltnm).
have lenm: n <=c m by move: ltnm => [h _].
move: (sE lenm); rewrite -/n; move=> <-.
clear sE.
set (G2:= injections (E +s1 a) F).
set (G1:= injections E F).
set rf:=Lf (restriction ^~ E) G2 G1.
have <-: (source rf = G2) by rewrite /rf; aw.
have <-: (target rf = G1) by rewrite /rf; aw.
have ta: lf_axiom (restriction ^~ E) G2 G1.
  move=> t /Zo_P [] /fun_set_P [ft st tt] it.
  have sat: sub E (source t) by rewrite st; fprops.
  move: (restriction_prop (proj1 it) sat) => pp.
  apply : Zo_i; first by apply /fun_set_P; ue.
  move: pp => [pa pb pc].
  split => //; move=> x y; rewrite pb => xE yE.
  rewrite restriction_V // restriction_V //.
  move: it=> [_ it]; apply: it; apply: sat=>//.
have fr: function rf by apply: lf_function.
apply: shepherd_principle =>//.
move=> x.
set(K:= inv_image_by_fun rf (singleton x)).
rewrite lf_target; move /Zo_P => [] /fun_set_P [fx sxE txF] injx.
have fst: finite_set (target x) by red;rewrite txF;fprops.
move:(cardinal_complement_image injx fst).
set (C:= F -s (image_of_fun x)).
rewrite sxE txF -/n -/m -/C => <-.
set (val:= Lf (Vf ^~ a) K C).
have tav:(lf_axiom (Vf ^~ a) K C).
  move => z /iim_fun_P [u /set1_P uz h1]; move: (Vf_pr fr h1).
  move: (p1graph_source fr h1); rewrite {1} /rf; aw => tG2.
  rewrite /rf; aw.
  move: tG2 => /Zo_P [] /fun_set_P [fz sz tgz] injz.
  have asz: inc a (source z) by rewrite sz; fprops.
  move => xx.
  apply /setC_P; split; first by rewrite -tgz;Wtac.
  move /(Vf_image_P1 fx) => [y ysx].
  have Ez: sub E (source z) by rewrite sz; fprops.
  have yE: inc y E by ue.
  rewrite -uz xx; rewrite restriction_V // => sW; symmetry in sW.
  move: injz=> [ _ hi]; move: (hi _ _ (Ez _ yE) asz sW) => ya.
  by case: naE; rewrite - ya.
have fv: function val by rewrite /val; apply: lf_function.
have sv: (source val = K) by rewrite /val; aw.
have tv: (target val = C) by rewrite /val; aw.
apply /card_eqP; exists val; split => //; apply: lf_bijective =>//.
  move=> u v /iim_fun_P [u' /set1_P usx Jg1].
  move => /iim_fun_P [v' /set1_P vsx Jg2] sv1.
  have uG2:inc u G2 by move:(p1graph_source fr Jg1); rewrite /rf; aw.
  have vG2:inc v G2 by move:(p1graph_source fr Jg2); rewrite /rf; aw.
  move: (Vf_pr fr Jg1) (Vf_pr fr Jg2); rewrite /rf lf_V // lf_V //.
  move: uG2 => /Zo_P [] /fun_set_P [fu su tu] inju.
  move: vG2 => /Zo_P [] /fun_set_P [fvv svv tvv] injv sr1 sr2.
  apply: function_exten=>//; try ue.
  move=> t; rewrite su; case /setU1_P; last by move=> ->.
  move=> tE.
  transitivity (Vf x t).
    rewrite - usx sr1 restriction_V //; rewrite su; fprops.
  rewrite - vsx sr2 restriction_V //; rewrite svv; fprops.
move=> y / setC_P [yF nyi].
have nasc: ~ (inc a (source x)) by ue.
set (f:= extension x a y).
have ff: function f by rewrite /f; apply: extension_f=>//.
have sf: source f = E +s1 a by rewrite /f /extension; aw; ue.
have tf: target f = F.
 by rewrite /f /extension; aw; rewrite txF; apply: setU1_eq.
have injf: injection f.
  split =>//; move=> u v;rewrite sf /f;case /setU1_P => xsf; case /setU1_P=>ysf.
  - rewrite !extension_Vf_in //; try ue; move: injx => [_ injx];apply: injx; ue.
  - rewrite - sxE in xsf.
    rewrite ysf extension_Vf_out // extension_Vf_in //.
    move=> eq; rewrite -eq in nyi; case: nyi.
    apply /(Vf_image_P1 fx); ex_tac; apply: W_pr3 =>//.
  - rewrite - sxE in ysf.
    rewrite xsf extension_Vf_out // extension_Vf_in //.
    move=> eq; rewrite eq in nyi; case: nyi.
    apply /(Vf_image_P1 fx);ex_tac; apply: W_pr3 =>//.
  - by rewrite xsf ysf.
have rFE:(restriction f E = x).
  have se: sub E (source f) by rewrite sf; fprops.
  move: (restriction_prop ff se) => [pa pb pc].
  apply: function_exten=>//; rewrite ? pb //.
    by rewrite pc tf txF.
    move=> u uE /=; rewrite restriction_V // /f extension_Vf_in//; ue.
have fG2: inc f G2.
  rewrite /G2/injections; apply: Zo_i=>//; apply /fun_set_P;split => //.
have fi:inc f (inv_image_by_fun rf (singleton x)).
  apply /iim_fun_P;exists x;fprops.
  have <-: (Vf rf f = x) by rewrite /rf lf_V//.
  apply: Vf_pr3=>//; rewrite /rf;aw.
ex_tac.
by rewrite /f extension_Vf_out.
Qed.

Lemma number_of_permutations E: finite_set E ->
  cardinal (permutations E) = (factorial (cardinal E)).
Proof.
move=> fsE.
have ->: (permutations E = injections E E).
  rewrite /permutations/injections.
  apply: Zo_exten1=> x; move /fun_set_P => [pa pb pc]; split.
     by case.
  apply: bijective_if_same_finite_c_inj =>//; [ rewrite pb pc // | ue ].
have aux: (cardinal E) <=c (cardinal E) by fprops.
rewrite (number_of_injections_prop fsE aux).
have cE: inc (cardinal E) Bnat by fprops.
rewrite /number_of_injections cdiff_n_n // factorial0 cquo_one //.
by apply: BS_factorial.
Qed.

Definition partition_with_pi_elements p E f :=
  [/\ domain f = domain p,
  (forall i, inc i (domain p) -> cardinal (Vg f i) = Vg p i) &
    partition_w_fam f E].

Definition partitions_pi p E :=
  Zo (gfunctions (domain p) (powerset E)) (partition_with_pi_elements p E).

Lemma partitions_piP p E f:
  inc f (partitions_pi p E) <-> partition_with_pi_elements p E f.
Proof.
split; first by case /Zo_P.
move=> h; apply: Zo_i =>//.
move: h => [p2 _ [p5 _ p7]].
set (g := triple (domain p) (powerset E) f).
have ->: (domain p = source g) by rewrite /g -p2; aw.
have ->: (powerset E = target g) by rewrite /g; aw.
have ->: (f = graph g) by rewrite /g; aw.
apply: gfun_set_i; apply: function_pr =>//.
move=> t. move/(range_gP p5) => [x xdf ->]; apply /setP_P.
move => y; rewrite -p7 => hh; union_tac.
Qed.

Lemma fif_cardinal i p:
  finite_int_fam p -> inc i (domain p) -> cardinalp (Vg p i).
Proof. by move=> [fgp alip fdp]; fprops. Qed.

Lemma pip_prop0 p E f: partition_with_pi_elements p E f ->
  forall i, inc i (domain f) -> sub (Vg f i) E.
Proof.
move=> [df cVg [fgf duj ue]].
move=>i idp t tW; rewrite -ue; union_tac.
Qed.

Lemma number_of_partitions1 p E:
  finite_int_fam p -> card_sum p = cardinal E ->
  nonempty (partitions_pi p E).
Proof.
move=> fif.
move /card_eqP => [f [[bf sjf] sf tg]].
pose k i := (Vg p i) *s1 i.
have sx: forall i, inc i (domain p) ->sub (k i) (source f).
  move=> i idp t tk; rewrite sf; apply /setUb_P1; ex_tac.
set g:= Lg (domain p) (fun i => image_by_fun f (k i)).
exists g; apply /partitions_piP; red.
split => //.
    rewrite /g; bw.
  move=> i idp; rewrite /g /k;bw.
  rewrite -{2} (card_card (fif_cardinal fif idp)).
  apply /card_eqP;eqsym;eqtrans ((Vg p i) *s1 i).
  apply: equipotent_restriction1 =>//; apply: sx =>//.
have ff: function f by fct_tac.
split => //.
    rewrite /g;fprops.
  rewrite /g.
  apply: mutually_disjoint_prop; bw.
  move=> i j y idp jdp; bw.
  move: (sx _ idp)(sx _ jdp)=> p1 p2.
  move => /(Vf_image_P ff (sx _ idp)) [u uki Wu].
  move => /(Vf_image_P ff (sx _ jdp)) [v vkj Wv].
  have uv: u = v.
     move: bf => [_ injf].
     rewrite Wv in Wu; apply: injf =>//;[apply:(p1 _ uki) | apply: (p2 _ vkj)].
  move: uki vkj; rewrite uv /k.
  by move /indexed_P => [_ _ <-] /indexed_P [_ _ <-].
rewrite /g -tg.
set_extens x.
  move /setUb_P; bw; move=> [y yd]; move: (sx _ yd) => aux; bw.
  move=> /(Vf_image_P ff aux) [u uk ->]; Wtac.
move=> xtf; move: ((proj2 sjf) _ xtf)=> [y ysf Wy].
move: ysf; rewrite sf; move /disjointU_P=> [pa pb pc].
apply /setUb_P1;ex_tac; apply /(Vf_image_P ff (sx _ pa)).
by rewrite /k;exists y => //; apply /indexed_P.
Qed.

Definition partitions_aux f g:=
  Lg (domain f) (fun i => image_by_fun g (Vg f i)).

Lemma number_of_partitions3 p E f g:
  partition_with_pi_elements p E f -> inc g (permutations E) ->
  inc (partitions_aux f g) (partitions_pi p E).
Proof.
move=> pip gp.
apply /partitions_piP.
move: gp => /Zo_P [] /fun_set_P [fg sg tg [ig sjg]].
have Ha:forall u, inc u (domain f) -> sub (Vg f u) (source g).
  rewrite sg; apply: (pip_prop0 pip).
move: pip => [df cVg [fgf duj ue]].
rewrite/partitions_aux.
red;bw; split => //.
  rewrite df;move=> i idp; bw; rewrite - (cVg _ idp) ; symmetry.
  apply /card_eqP.
  apply: equipotent_restriction1 =>//; apply: Ha =>//; ue.
split;fprops.
  apply: mutually_disjoint_prop=>//.
  bw; move=> i j y idp jdp.
  move: (Ha _ idp) (Ha _ jdp)=> s1 s2.
  bw; move=> /(Vf_image_P fg s1) [u ui Wu] /(Vf_image_P fg s2) [v vi Wv].
  have uv: u = v.
    move: ig => [_ ig]; rewrite Wv in Wu;apply: ig; fprops.
  red in duj; case: (duj _ _ idp jdp)=> // ns.
  rewrite /Vf in ui vi; rewrite -uv in vi.
  red in ns; empty_tac1 u.
rewrite -tg;set_extens x.
  move /setUb_P1 => [y ydp].
  move /(Vf_image_P fg (Ha _ ydp)) => [u ua ->]; Wtac; exact: (Ha _ ydp).
move=> xtg; move: ((proj2 sjg) _ xtg)=> [y ysf Wy].
move: ysf; rewrite sg -ue;move=> /setUb_P [t tf etc].
apply /setUb_P1; ex_tac; apply /(Vf_image_P fg (Ha _ tf)); ex_tac.
Qed.

Lemma number_of_partitions4 p E f:
  finite_int_fam p -> card_sum p = cardinal E ->
  partition_with_pi_elements p E f ->
  surjection (Lf (partitions_aux f)
    (permutations E) (partitions_pi p E)).
Proof.
move=> fip spE [df cVg pfa];move:(pfa)=> [fgf duj ue].
set phi:=Lf _ _ _.
apply: lf_surjective; first by move=> g; apply: number_of_partitions3 =>//.
have Ha:finite_set E by red;rewrite - spE; apply /BnatP /finite_sum_finite.
move=> y /partitions_piP [dy cVy [fgy dujy uey]].
pose ha i := equipotent_ex (Vg f i) (Vg y i).
have hap: forall i, inc i (domain p) ->
    bijection_prop (ha i) (Vg f i) (Vg y i).
   move=> i idp; rewrite /ha; apply: equipotent_ex_pr.
   by apply /card_eqP; rewrite (cVg _ idp) (cVy _ idp).
pose h i := Lf (Vf (ha i)) (Vg f i) E.
have ta1:forall i, inc i (domain p) -> lf_axiom (Vf (ha i)) (Vg f i) E.
  move=> i idp z zW.
  move: (hap _ idp)=> [[[fh _] _] sh th].
  rewrite - sh in zW;move: (Vf_target fh zW); rewrite th -uey.
  move=> h1; apply /setUb_P; exists i => //; ue.
have fp1:(forall i, inc i (domain f) -> function_prop (h i) (Vg f i) E).
  rewrite df /h=> i idp; split; aw; apply: lf_function; apply: ta1 =>//.
rewrite -df in hap.
move: (extension_partition1 pfa fp1).
set g := common_ext _ _ _; move=> [[fg sg tg] extg].
have injg: injection g.
  split=> //; move=> u v.
  rewrite sg -ue; move=> /setUb_P [u' u'd Vu'] /setUb_P [v' v'd Vv'].
  have pu : Vf g u = Vf (ha u') u.
    move: (extg _ u'd) => [p1 p2 ->] //;rewrite /h; aw; apply: ta1; ue.
  have pv: Vf g v = Vf (ha v') v.
    move: (extg _ v'd)=> [p1 p2 -> ] //; rewrite /h; aw; apply: ta1; ue.
  move=> eq; suff:u' = v'.
    move: (hap _ u'd) => [[[_ ih] _] sa _] aux.
    by rewrite sa in ih; apply: ih =>//; rewrite - ? pu ? aux // eq pv.
  case: (duj _ _ u'd v'd) =>// dj.
  have Wu: (inc (Vf g u) (Vg y u')).
    rewrite pu; move: (hap _ u'd) => [[fh _] sa <-]; Wtac; fct_tac.
  have Wv: (inc (Vf g v) (Vg y v')).
    rewrite pv; move: (hap _ v'd) => [[fh _] sa <-]; Wtac; fct_tac.
  red in dujy; rewrite dy -df in dujy.
  case: (dujy _ _ u'd v'd) =>//.
  move=> h1; rewrite eq in Wu; empty_tac1 (Vf g v).
have bx: (bijection g).
  apply: bijective_if_same_finite_c_inj=>//; [ by rewrite sg tg | ue].
have pg: inc g (permutations E) by apply: Zo_i=>//; apply /fun_set_P.
ex_tac.
symmetry.
rewrite /partitions_aux; apply: fgraph_exten =>//; [ fprops | bw; ue|].
bw; move=> x xdf; bw.
move: (hap _ xdf) => [bha sha tha].
move: (fp1 _ xdf) (extg _ xdf) => [fh sh th] [p2a _ p2c].
have p3 : forall i, inc i (Vg f x) -> Vf g i = Vf (ha x) i.
  move=> i ins; rewrite (p2c _ ins).
  by rewrite /h; aw; apply: ta1 =>//; ue.
rewrite -tha.
set_extens u; bw.
   move /(Vf_image_P fg p2a)=> [i ins ->]; rewrite (p3 _ ins); Wtac;fct_tac.
move: bha => [iha sjha] ut.
move: ((proj2 sjha) _ ut)=> [v vs Wv].
rewrite sha in vs; rewrite - Wv - (p3 _ vs); apply /(Vf_image_P fg p2a).
by ex_tac; apply: Vf_pr3 =>//; apply: p2a.
Qed.

Lemma number_of_partitions5P p E f g h:
  finite_int_fam p -> card_sum p = cardinal E ->
  partition_with_pi_elements p E f ->
  inc h (permutations E) -> inc g (permutations E) ->
 ( (partitions_aux f g = partitions_aux f h) <->
  (forall i, inc i (domain p) ->
      image_by_fun ( (inverse_fun h) \co g) (Vg f i) = (Vg f i))).
Proof.
move=> fip spE pip; move: (pip_prop0 pip)=> Ht.
move: pip => [df cVg [fgf duj ue]].
move => /Zo_P [] /fun_set_P [fh sh th] bh.
move => /Zo_P [] /fun_set_P [fg sg tg] bg.
have fih: function (inverse_fun h) by apply: bijective_inv_f.
have cih: (inverse_fun h) \coP g by split => //; aw; ue.
have fcih : function ((inverse_fun h) \co g) by fct_tac.
rewrite -df; split.
  move=> eq i idp; move: (f_equal (Vg ^~ i) eq);rewrite /partitions_aux; bw.
  move=> eql;rewrite /image_by_fun/inverse_fun/compose; aw.
  set_extens x.
    move /dirim_P => [y yW /compg_pP [z pa /igraph_pP pb]].
    have : inc z (image_by_fun g (Vg f i)) by apply /dirim_P; ex_tac.
    rewrite eql; move /dirim_P => [x' x'Vf Jg2].
    move: bh => [injh _]; rewrite (injective_pr3 injh pb Jg2) //.
  move=> xW.
  have xsh: inc x (source h) by rewrite sh; apply: (Ht _ idp).
  have : (inc (Vf h x) (image_by_fun h (Vg f i))).
     apply /dirim_P; ex_tac; Wtac.
  rewrite -eql; move /dirim_P => [x' x'Vf Jg].
  apply /dirim_P; ex_tac; apply /compg_pP; ex_tac; apply /igraph_pP;Wtac.
move=> aux; apply: Lg_exten.
move=> i xdp; move: (aux _ xdp) => aux'.
set_extens x.
  move /(dirim_P) => [y yVf Jg].
  have xt:inc x (target h)
     by rewrite th -tg ;apply: (p2graph_target fg Jg).
  move: (p1graph_source fg Jg) =>ys.
  move: bh=> [_ sjh]; move: ((proj2 sjh) _ xt)=> [z zs Wz].
  have p2: inc (J z x) (graph h) by rewrite -Wz;apply: Vf_pr3 =>//.
  apply /dirim_P; ex_tac; rewrite -(aux _ xdp).
  apply /dirim_P; exists y => //; rewrite corresp_g; apply /compg_pP.
  by exists x=> //; rewrite /inverse_fun; aw; apply /igraph_pP.
rewrite -{1} aux'/image_by_fun/compose /inverse_fun.
rewrite !corresp_g; move /(dirim_P)=> [u] /(dirim_P) [v Jg].
move /compg_pP =>[w pa /igraph_pP pb] pc.
apply /dirim_P; ex_tac.
rewrite - (fgraph_pr _ pb pc); fprops.
Qed.

Lemma number_of_partitions6 p E f h:
  finite_int_fam p -> card_sum p = cardinal E ->
  partition_with_pi_elements p E f ->
  inc h (permutations E) ->
  lf_axiom (fun g=> Lg (domain p)(fun i=> (restriction2
    ((inverse_fun h) \co g)
    (Vg f i) (Vg f i))))
  (Zo (permutations E)
    (fun g => (partitions_aux f g = partitions_aux f h)))
  (productb (Lg (domain p)(fun i=> (permutations (Vg f i))))).
Proof.
move=> fip spE pip hp g; move: (pip_prop0 pip)=> Ht.
move: (pip) => [df cVg [fgf duj ue]].
move /Zo_P => [gp eql]; apply /setXb_P; fprops;split;fprops; bw.
move=> i idp; bw.
move: eql; move /(number_of_partitions5P fip spE pip hp gp) => eql.
move: (eql _ idp) => ic; clear eql.
move: hp gp => /Zo_P [] /fun_set_P [fh sh th] bh.
move=> /Zo_P [] /fun_set_P [fg sg tg] bg.
have fih: function (inverse_fun h) by apply: bijective_inv_f.
have cih: (inverse_fun h) \coP g by split => //; aw; ue.
have fcih : function ((inverse_fun h) \co g) by fct_tac.
set k:= restriction2 _ _ _.
have sk: source k = Vg f i by rewrite /k/restriction2; aw.
have tk: target k = Vg f i by rewrite /k/restriction2; aw.
rewrite df in Ht; move: (Ht _ idp) => Ht1.
have ra: (restriction2_axioms (compose (inverse_fun h) g) (Vg f i) (Vg f i)).
   red; aw; split => //; ue.
have fk: (function k) by rewrite /k; apply: (proj31(restriction2_prop ra)).
apply: Zo_i; first by apply /fun_set_P;split => //.
apply: bijective_if_same_finite_c_inj.
    by rewrite sk tk.
  red;rewrite sk; move: fip=> [hp _ ]; move: (hp _ idp).
  by move: pip => [_ pip _];rewrite (pip _ idp); fprops.
split=>// x y; rewrite sk => xsk ysk.
rewrite /k restriction2_V //restriction2_V //.
move: (Ht1 _ xsk) (Ht1 _ ysk); rewrite - sg => xsg ysg.
aw;move => eq.
move: bg=> [[_ ig] _ ]; apply: ig =>//.
move: (inverse_bij_fb bh) => [[_ iih] _ ].
move:iih; aw; apply =>//; try (rewrite th -tg; Wtac).
Qed.

Lemma number_of_partitions7 p E f h:
  finite_int_fam p -> card_sum p = cardinal E ->
  partition_with_pi_elements p E f ->
  inc h (permutations E) ->
  bijection (Lf (fun g=> Lg (domain p)(fun i=> (restriction2
    ((inverse_fun h) \co g)
    (Vg f i) (Vg f i))))
  (Zo (permutations E)
    (fun g => (partitions_aux f g = partitions_aux f h)))
  (productb (Lg (domain p)(fun i=> (permutations (Vg f i)))))).
Proof.
move=> fip spE pip hp; move: (pip_prop0 pip)=> sWE.
move: (pip) => [df cVg [fgf duj ue]].
rewrite df in sWE.
set ww:=Lf _ _ _.
move: (number_of_partitions6 fip spE pip hp) => ta.
move:(hp) => /Zo_P [] /fun_set_P [fh sh th] bh.
have bih: (bijection (inverse_fun h)) by apply: inverse_bij_fb.
have fw: function ww by rewrite /ww; apply: lf_function.
move: (pip) => [_ _ pfa].
have sw: surjection ww.
  split => //.
  rewrite /ww lf_source lf_target => y.
  set xxx := Lg _ _; have fgg: fgraph xxx by rewrite /xxx; fprops.
  move /setXb_P; rewrite /xxx; clear fgg xxx; bw.
  move=> [fgy dy yp].
  set (ha := fun i=> Vg y i).
  have yp': (forall i, inc i (domain p) ->
    (bijection_prop (ha i) (Vg f i) (Vg f i))).
    move=> i idp;move: (yp _ idp); bw.
     move => /Zo_P [] /fun_set_P [pa pb pc]; split => //.
  pose hb i := Lf (Vf (ha i)) (Vg f i) E.
  have ta1: (forall i, inc i (domain p) -> lf_axiom (Vf (ha i)) (Vg f i) E).
    move=> i idp z zW; move: (yp' _ idp)=> [bha sha tha].
    apply: (sWE _ idp); rewrite -tha;Wtac; fct_tac.
  have Hw:forall i, inc i (domain f) -> function_prop (hb i) (Vg f i) E.
    rewrite df; move => i ip; rewrite /hb /function_prop lf_source lf_target.
    split => //; apply: lf_function;apply: ta1 =>//.
  move: (extension_partition1 pfa Hw).
  set g := common_ext _ _ _; move => [[fg sg tg] alag].
  have ijg: injection g.
    split=>// u v; rewrite sg => uE vE.
    move: uE vE;rewrite -ue; move=> /setUb_P [a adf ua] /setUb_P [b bdf vb].
    move: (alag _ adf)(alag _ bdf) => [p1 p2 p3] [q1 q2 q3].
    have ap: inc a (domain p) by ue.
    have bp: inc b (domain p) by ue.
    rewrite (p3 _ ua)(q3 _ vb).
    move : (ta1 _ ap) (ta1 _ bp) => ta2 ta3.
    rewrite /hb (lf_V ta2 ua) (lf_V ta3 vb).
    move: (yp' _ ap) (yp' _ bp)=> [[[_ iha] xx] sha tha] [yy shb thb].
    case: (duj _ _ adf bdf).
      move=> ab; rewrite -ab in vb; rewrite -ab.
      apply: iha; rewrite sha //.
    move=> h1 h2; empty_tac1 (Vf (ha a) u).
     rewrite /Vf in tha;rewrite -tha; Wtac; fct_tac.
     rewrite /Vf in thb;rewrite h2 -thb; Wtac; fct_tac.
  have bg: (bijection g).
    apply: bijective_if_same_finite_c_inj; last by exact.
       rewrite sg tg //.
    rewrite sg; apply /BnatP; rewrite - spE; apply: finite_sum_finite =>//.
  have pa:forall i v, inc i(domain p) -> inc v (Vg f i)-> Vf g v = Vf (ha i) v.
    rewrite -df;move=> i v idp; move: (alag _ idp).
    rewrite /agrees_on; move => [s1 s2 aux].
    move=> vW; move: (aux _ vW); rewrite /hb lf_V;
       [done | apply: ta1;ue| done ].
  have pb:forall i v, inc i (domain p)-> inc v (Vg f i) -> inc (Vf g v)(Vg f i).
    move=> i v ip iv; rewrite (pa _ _ ip iv).
    move: (yp' _ ip) => [bha sha tha]; Wtac; fct_tac.
  have chg: (h \coP g) by split => //;ue.
  have fhg: function (h \co g) by fct_tac.
  have bhg: (bijection (h \co g)) by apply: compose_fb.
  set (t:= h \co g).
  have pt: inc t (permutations E).
    apply: Zo_i => //; apply /fun_set_P; red;rewrite /t; aw; split => //.
  set z:=Zo _ _.
  have xz:inc t z.
    apply: Zo_i => //.
    rewrite /partitions_aux df; apply: Lg_exten.
    move=> i idp /=; set_extens u; aw.
      move /dirim_P => [a ai]; rewrite /t /compose; aw.
      move /compg_pP => [b Jg1 Jg2]; apply /dirim_P; ex_tac.
      by move: (Vf_pr fg Jg1) => ->; apply: pb.
    move=> /dirim_P [a asVf Jg].
    have atg: inc a (target g) by rewrite tg; apply: (sWE _ idp).
    move: (bg) => [_ sjg]; move: ((proj2 sjg) _ atg) => [b bsg Wb].
    move: (bsg); rewrite sg; rewrite -ue; move /setUb_P => [j jd bW].
    apply /dirim_P.
    rewrite -df in idp; case: (duj _ _ idp jd).
      move=> eq; rewrite -eq in bW; ex_tac.
      rewrite /t /compose; aw; apply /compg_pP; ex_tac; rewrite -Wb; Wtac.
    move=> di; empty_tac1 a.
    rewrite -df in pb; rewrite -Wb;apply: (pb _ _ jd bW).
  ex_tac; rewrite (lf_V ta xz).
  have ->: ( (inverse_fun h) \co t = g).
   rewrite /t (compfA (composable_inv_f bh) chg).
   rewrite bij_left_inverse // sh -tg compf_id_l //.
  apply: fgraph_exten;bw; fprops.
  move=> x xdp; bw.
  move: (sWE _ xdp)=> Wf.
  have ra: (restriction2_axioms g (Vg f x) (Vg f x)).
   have ssg: sub (Vg f x) (source g) by rewrite sg.
   have stg: sub (Vg f x) (target g) by rewrite tg.
   split => //; move=> u /(Vf_image_P fg ssg) [v vW ->]; apply: (pb _ _ xdp vW).
  move : (yp' _ xdp); rewrite /ha; move=> [bha sha tha].
  bw; apply: function_exten.
  - by apply: (proj31 (restriction2_prop ra)).
  - fct_tac.
  - by rewrite /restriction2 sha corresp_s.
  - by rewrite /restriction2 tha corresp_t.
  - rewrite /restriction2; aw; move=> u uW /=; rewrite restriction2_V //.
    by rewrite (pa _ _ xdp uW).
split=>//; split =>//.
rewrite /ww lf_source=> x y xS yS; rewrite (lf_V ta xS) (lf_V ta yS).
move: xS yS => /Zo_P [xs eq1] /Zo_P [ys eq2].
move: eq1 => /(number_of_partitions5P fip spE pip hp xs) => eq1.
move: eq2 => /(number_of_partitions5P fip spE pip hp ys) => eq2.
move: eq1 eq2.
set xi:= _ \co x; set yi:= _ \co y => eq1 eq2.
have shi: (source (inverse_fun h)= E) by aw.
have thi: (target (inverse_fun h)= E) by aw.
move: xs ys => /Zo_P [] /fun_set_P [fx sx tx] bx
     /Zo_P [] /fun_set_P [fy sy ty] bjy eq.
have Hx: (inverse_fun h) \coP x by split => //;[ fct_tac | ue].
have Hy: (inverse_fun h) \coP y by split => //;[ fct_tac | ue].
suff: xi = yi.
  rewrite /xi /yi;move => eqi; move: (f_equal (compose h) eqi).
  move: (composable_f_inv bh) => co.
  rewrite (compfA co Hx) (compfA co Hy) (bij_right_inverse bh).
  by rewrite th -{1} tx -ty (compf_id_l fx) (compf_id_l fy).
have fxi: function xi by rewrite/xi; apply: compf_f=>//.
have fyi: function yi by rewrite/xi; apply: compf_f=>//.
have sxi: source xi = E by rewrite /xi compf_s.
have syi: source yi = E by rewrite /yi compf_s.
have txi: target xi = E by rewrite /xi compf_t.
have tyi: target yi = E by rewrite /yi compf_t.
apply: (function_exten fxi fyi); [ by rewrite syi | by rewrite tyi| ].
rewrite sxi -ue;move=> u; move /setUb_P; rewrite df; move=> [i ip iW].
move: (f_equal (Vg ^~i) eq); bw => eq3.
have ra:restriction2_axioms xi (Vg f i) (Vg f i).
  split => //; last (by rewrite eq1; fprops);
  rewrite ?sxi ?txi; apply: (sWE _ ip).
have rb:restriction2_axioms yi (Vg f i) (Vg f i).
  split => //; last (by rewrite eq2; fprops);
    rewrite ? syi ? tyi; apply: (sWE _ ip).
move: (f_equal (Vf ^~u) eq3);rewrite restriction2_V // restriction2_V //.
Qed.

Theorem number_of_partitions p E:
  finite_int_fam p -> card_sum p = cardinal E ->
  let num:= factorial (cardinal E) in
    let den := card_prod (Lg (domain p) (fun z => factorial (Vg p z)))
      in (
        [/\ num = cardinal (partitions_pi p E) *c den ,
        inc num Bnat, inc den Bnat, den <> card_zero &
        finite_set (partitions_pi p E)]).
Proof.
move => fip spe num den.
move: (number_of_partitions1 fip spe)=> [h hp].
have Hb: finite_set E.
  by red; rewrite - spe; apply /BnatP; apply: finite_sum_finite=> //.
have numB: inc num Bnat by rewrite /num; apply: BS_factorial; apply /BnatP; aw.
have ndenB: inc den Bnat.
  move: fip=> [p2 p3].
  rewrite /den;apply: finite_product_finite =>//.
  by red; bw;split => //; red; bw => i idp; bw; apply: BS_factorial; apply: p2.
have nd:den <> \0c.
  apply /cprod_nzP; red;bw.
  move: fip=> [p2 p3].
  red;move=> i idp; bw; apply: factorial_nz; apply: p2=>//.
rewrite /finite_set.
set aux:= cardinal _.
suff: num = aux *c den.
  move => eql; split => //.
  rewrite eql in numB.
  have ca: cardinalp aux by rewrite /aux; fprops.
  apply /BnatP; apply: (Bnat_in_product ca nd numB).
move: hp => /Zo_P [hfpp pip].
move:(number_of_partitions4 fip spe pip).
set phi:= Lf _ _ _; move=> sjphi.
have caux:(forall w, bijection w -> cardinal (source w) = cardinal (target w)).
  by move=> w bw; apply /card_eqP; exists w; split => //.
suff phip: forall x, inc x (target phi) ->
    cardinal (inv_image_by_fun phi (singleton x)) = den.
  move: sjphi=> [fphi _].
  move:(shepherd_principle fphi phip).
  rewrite /phi lf_source lf_target number_of_permutations //.
move=> x xt.
move:((proj2 sjphi) _ xt) => [y ys yw].
move: ys; rewrite {1}/ phi; aw => yp.
move: (number_of_partitions7 fip spe pip yp) => baux.
move: (caux _ baux); rewrite lf_source lf_target; clear baux.
set d:= cardinal (productb _).
have ->: d = den.
  apply/card_eqP; apply: equipotent_setXb; split;fprops; bw.
  move=> i idp; bw.
  move: pip fip=>[p1 p2 [p3 _ _]] [q2 q3].
  apply /card_eqP; rewrite number_of_permutations.
    rewrite (p2 _ idp).
    set (t := (factorial (Vg p i))).
    have ct: cardinalp t by move: (BS_factorial (q2 _ idp)); fprops.
    by symmetry; apply: card_card.
  red; rewrite p2 //; apply /BnatP; apply: q2 =>//.
move => <-; set z := Zo _ _.
have Ha:lf_axiom (fun g =>
     (partitions_aux h g)) (permutations E) (partitions_pi p E).
  move => g gp; apply: number_of_partitions3 =>//.
apply: f_equal.
have fphi: function phi by fct_tac.
set_extens t.
  move /(iim_fun_set1_P _ fphi) => []; rewrite /phi lf_source => ta; aw => tb.
  apply: Zo_i => //; rewrite - tb -yw /phi; aw.
move /Zo_P => [pa pb].
apply: (iim_fun_set1_i fphi); rewrite /phi; aw.
by rewrite -yw /phi; aw.
Qed.

Theorem number_of_partitions_bis p E:
  finite_int_fam p -> card_sum p = cardinal E ->
  cardinal (partitions_pi p E) =
  (factorial (cardinal E)) %/c
           (card_prodb (domain p) (fun z => factorial (Vg p z))).
Proof.
move=> h1 h2.
move: (number_of_partitions h1 h2); simpl.
set (x1:= cardinal (partitions_pi p E)).
set x2:= card_prod _.
move=> [p1 p2 p3 p4] /BnatP p5.
rewrite p1 cprodC; symmetry; apply: cdivides_pr4 =>//.
Qed.

Lemma number_of_partitions_p2 E m p:
 inc m Bnat -> inc p Bnat -> cardinal E = (m +c p) ->
 let num := factorial (m +c p) in
 let den := (factorial m) *c (factorial p) in
 let x := cardinal (partitions_pi (variantLc m p) E) in
   [/\ inc x Bnat, num = x *c den,
      inc num Bnat, inc den Bnat & den <> \0c].
Proof.
move=> mB pB cE num den.
set P:= variantLc m p.
move=> x.
have h1: finite_int_fam P.
  rewrite /P;split;fprops.
  by red; bw; move=> i it; try_lvariant it; rewrite - inc_Bnat.
  bw;apply: set2_finite.
have p2: card_sum P = cardinal E.
  symmetry;rewrite cE /card_sum2/card_sum; fprops.
move: (number_of_partitions h1 p2); simpl.
set y:= card_prod _.
have -> : den = y.
  rewrite /den/card_prod2/y/P; bw.
  apply: f_equal; apply: fgraph_exten; fprops; bw.
  move=> xx xtp /=; try_lvariant xtp; fprops.
rewrite cE; move=> [r1 r2 r3 r4 r5];split;fprops.
Qed.

Binomial coefficient

Definition binom n m :=
  Vg (induction_term
      (fun _ T: Set => Lg Bnat (fun z => variant \0c \1c
          (Vg T z +c Vg T (cpred z)) z))
       (Lg Bnat (variant \0c \1c \0c))
       n) m.

Lemma binom00: binom \0c \0c = \1c.
Proof.
by rewrite /binom induction_term0 /variant; bw; [ Ytac0 | fprops ].
Qed.

Lemma binom0Sm m: inc m Bnat ->
  binom \0c (succ m) = \0c.
Proof.
move=> mBnat.
rewrite /binom /variant induction_term0; bw; last by fprops.
have snz: succ m <> \0c by apply: succ_nz.
by Ytac0.
Qed.

Lemma binomSn0 n: inc n Bnat-> binom (succ n) \0c = \1c.
Proof.
move=> nB; rewrite /binom /variant induction_terms //.
bw; [by Ytac0 | fprops]; fprops.
Qed.

Lemma binomSnSm n m: inc n Bnat-> inc m Bnat ->
  binom (succ n) (succ m) = (binom n (succ m)) +c (binom n m).
Proof.
move=> nB mB.
rewrite /binom /variant induction_terms //.
set T := induction_term _ _.
have snz: succ m <> \0c by apply: succ_nz.
bw; [Ytac0; rewrite cpred_pr1 //; fprops | fprops ].
Qed.

Lemma BS_binom n m: inc n Bnat -> inc m Bnat ->
  inc (binom n m) Bnat.
Proof.
move=> nB; move: n nB m.
apply: cardinal_c_induction.
  apply: cardinal_c_induction.
      rewrite binom00=>//; fprops.
    move => n nB _; rewrite binom0Sm=>//; fprops.
move => n nB hrec; apply: cardinal_c_induction.
  rewrite binomSn0=>//; fprops.
move => p pB bB.
rewrite binomSnSm=>//; fprops.
Qed.

Lemma binom_alt_pr n m: inc n Bnat -> inc m Bnat ->
  (binom n m) *c (factorial m) *c (factorial (n -c m)) =
  Yo (m <=c n) (factorial n) \0c.
Proof.
move: n m.
pose Bi n m := (binom n m) *c
     (factorial m *c (factorial (n -c m))).
have ba4: forall n m, inc n Bnat -> inc m Bnat -> Bi (succ n) (succ m)=
    ((Bi n (succ m)) *c (Yo (n <=c m) \1c (n -c m)))
   +c (Bi n m *c succ m).
  move=> n m nB mB.
  set (x:= Bi n m); set (y:= Bi n (succ m)).
  rewrite /Bi binomSnSm //.
  rewrite cdiff_pr6 =>//.
  set aux := (factorial (succ m)) *c (factorial (n -c m)).
  rewrite cprod_sumDr.
  set A:= (binom n (succ m)) *c aux.
  set (AA:= y *c (Yo (n <=c m) \1c (n -c m))).
  suff: A = AA.
    move=> ->; rewrite /x /Bi - cprodA; congr (_ +c (_ *c _)).
    rewrite (cprodC (factorial m) _) - cprodA -(factorial_succ mB).
    rewrite cprodC//.
  rewrite /A /AA /y /Bi; rewrite /aux - ! cprodA; congr (_ *c (_ *c _)).
  have nsmB: inc (n -c (succ m)) Bnat by fprops.
  case: (p_or_not_p (n <=c m)) => le.
    have cf: cardinalp (factorial (n -c (succ m))).
      apply: CS_Bnat;apply: (BS_factorial nsmB).
    Ytac0; rewrite (cprod1r cf).
    have nel:= (card_leT le (card_le_succ mB)).
    rewrite (cdiff_wrong nel).
    case: (equal_or_not n m) => eq.
     rewrite eq cdiff_n_n =>//.
    rewrite cdiff_wrong; fprops; move=> el; case: eq; co_tac.
  Ytac0.
  have sm: (succ m) <=c n.
    case: (Bnat_to_el nB mB); first by move => nle; contradiction.
    by move /(card_le_succ_ltP _ mB).
  move: (csucc_diff nB mB sm) => s.
  rewrite {1} s factorial_succ -? s; [ trivial | fprops].
move=> n m nB mB.
rewrite - cprodA; change (Bi n m = Yo (m <=c n) (factorial n) \0c).
move: n nB m mB; apply: cardinal_c_induction.
  move=> m mB.
  move: (BS_factorial mB) => fi.
  have fc: cardinalp (factorial m) by fprops.
  have cs: (\0c -c m) = \0c by rewrite cdiff_wrong; fprops.
  rewrite /Bi cs factorial0 (cprod1r fc) {fi fc cs}.
  move: m mB; apply: cardinal_c_induction.
    rewrite binom00 factorial0; aw; fprops.
    rewrite Y_true; fprops.
  move=> p pB aux.
  have ns: ~ (succ p) <=c \0c.
    move /(card_le_succ_lt0P (CS_Bnat pB) BS0)=> h';apply: (card_lt0 h').
  by Ytac0;rewrite binom0Sm //cprodC cprod0r.
move=> N NB rN; apply: cardinal_c_induction.
  move: (BS_succ NB) => sB.
  rewrite /Bi (binomSn0 NB) factorial0.
  rewrite (cdiff_n_0 sB).
  rewrite (cprod1l (CS_Bnat (BS_factorial sB))).
  rewrite (cprod1l (CS_Bnat (BS_factorial sB))).
  rewrite Y_true//; fprops.
move => p pB bB.
have spN: inc (succ p) Bnat by fprops.
rewrite (ba4 _ _ NB pB).
rewrite (rN _ pB)(rN _ spN) factorial_succ //.
have Nc: cardinalp N by fprops.
have psc: cardinalp (succ p) by fprops.
have cp: cardinalp p by fprops.
move: (card_lt_succ pB) => psp.
move: (card_le_succ_succP cp (CS_Bnat NB)) => hlp.
case: (card_le_to_el psc Nc) => c1.
  have [pN npN]: p <c N by co_tac.
  have yf:~ (N <=c p) by dneg eql; co_tac.
  Ytac0; Ytac0; Ytac0; move: (pN); move / hlp => pN1; Ytac0.
   rewrite - cprod_sumDl.
  by apply: f_equal; rewrite (Bsucc_rw pB) (Bsucc_rw NB) csumA cdiff_rpr.
have r1: ~ ((succ p) <=c N) by move=> h; co_tac.
Ytac0; rewrite cprodC cprod0r.
move: c1 => /(card_lt_succ_leP pB) c1.
case: (equal_or_not p N) => epN.
  have c2: p <=c N by rewrite epN; fprops.
  move: (c2); rewrite {1} hlp => c2'.
  Ytac0; Ytac0; rewrite epN.
  rewrite csum0l => //; fprops.
have c2: ~(p <=c N) by dneg c3; co_tac.
move: (c2); rewrite {1} hlp => c2'.
Ytac0; Ytac0; rewrite cprodC cprod0r //.
by rewrite (bsum0l BS0).
Qed.

Lemma binom_bad n m: inc n Bnat -> inc m Bnat ->
  n <c m -> binom n m = \0c.
Proof.
move=> nB mB h; move: (binom_alt_pr nB mB).
have nz: ~ (m <=c n) by move=> h'; co_tac.
Ytac0;move=> p1; ex_middle p2.
have nmB: inc (n -c m) Bnat by fprops.
move: (cprod2_nz (cprod2_nz p2 (factorial_nz mB)) (factorial_nz nmB))=> z4.
contradiction.
Qed.

Lemma binom_good n m: inc n Bnat -> inc m Bnat ->
  m <=c n ->
  (binom n m) *c (factorial m) *c (factorial (n -c m)) = (factorial n).
Proof. by move=> nB mB h; move: (binom_alt_pr nB mB); Ytac0. Qed.

Lemma binom_pr0 n p: inc n Bnat -> inc p Bnat ->
  p <=c n ->
  let num := (factorial n) in
  let den:= (factorial p) *c (factorial (n -c p)) in
  den %|c num /\ binom n p = num %/c den.
Proof.
move=> nB pB h num den; move: (binom_good nB pB h).
rewrite -/num -/den.
have nuB: inc num Bnat by apply: BS_factorial =>//.
have deB: inc den Bnat by apply: BS_prod;apply: BS_factorial =>//; fprops.
have dnz: den <> \0c.
   rewrite /den; apply: cprod2_nz; apply: factorial_nz; fprops.
have bN: inc (binom n p) Bnat by apply: BS_binom =>//.
rewrite - cprodA cprodC.
move => rel; split.
  rewrite -rel;apply: cdivides_pr1 =>//.
apply: cdivides_pr2 => //.
Qed.

Lemma binom_pr1 n p: inc n Bnat -> inc p Bnat ->
  p <=c n ->
  binom n p = (factorial n) %/c ((factorial p) *c (factorial (n -c p))).
Proof.
by move=> nB pB h; move: (binom_pr0 nB pB h)=> [_].
Qed.

Lemma binom_symmetric n p: inc n Bnat -> inc p Bnat ->
  p <=c n -> binom n p = binom n (n -c p).
Proof.
move => nB pB h.
move: (cdiff_le_symmetry h) => aux.
move: (cdiff_le_symmetry h) => h'.
rewrite (binom_pr1 nB pB h) cprodC (binom_pr1 nB (BS_diff p nB) h').
rewrite double_diff //; apply: le_minus.
Qed.

Lemma binom_symmetric2 n m: inc n Bnat -> inc m Bnat ->
    binom (n +c m) m = binom (n +c m) n.
Proof.
move => nB mB.
rewrite csumC (binom_symmetric (BS_sum mB nB) mB (Bsum_M0le mB nB)).
rewrite csumC (cdiff_pr1 nB mB) //.
Qed.

Lemma binom0 n: inc n Bnat -> binom n \0c = \1c.
Proof.
move=> nB.
case: (equal_or_not n \0c).
  by move=> ->; rewrite binom00.
move=> nz; move: (cpred_pr nB nz)=> [pB] ->.
rewrite binomSn0 //.
Qed.

Lemma binom1 n: inc n Bnat -> binom n \1c = n.
Proof.
move: n; rewrite - succ_zero;apply: cardinal_c_induction.
  rewrite binom0Sm //; fprops.
move=> p pB r.
by rewrite (binomSnSm pB BS0) r (binom0 pB) (Bsucc_rw pB).
Qed.

Lemma binom2a n: inc n Bnat ->
  \2c *c (binom (succ n) \2c) = n *c (succ n).
Proof.
move:n ; rewrite -{2} succ_one; apply: cardinal_c_induction.
  symmetry;rewrite cprodC cprod0r.
  rewrite binomSnSm; fprops.
  rewrite binom0Sm; fprops; rewrite binom1;fprops.
  by aw;fprops;rewrite cprod0r.
move=> n nB r; move: (BS_succ nB) => sB.
rewrite (binomSnSm sB BS1).
rewrite cprod_sumDl r (binom1 sB).
rewrite - cprod_sumDr cprodC.
by congr (_ *c _);rewrite - card_two_pr (Bsucc_rw sB) (Bsucc_rw nB) csumA.
Qed.

Lemma binom2 n: inc n Bnat ->
  binom (succ n) \2c = (n *c (succ n)) %/c \2c.
Proof.
move=> nB; move: (BS_succ nB) => sB.
apply: (cdivides_pr2 (BS_prod nB sB) BS2 (BS_binom sB BS2) card2_nz).
by rewrite (binom2a nB).
Qed.

Lemma binom_nn n: inc n Bnat -> binom n n = \1c.
Proof.
move=> nB.
have nn: n <=c n by fprops.
rewrite binom_symmetric// cdiff_n_n //; apply: binom0 =>//.
Qed.

Lemma binom_pr3 n p: inc n Bnat -> inc p Bnat ->
  p <=c n -> binom n p <> \0c.
Proof.
move=> nB pB h bz; move: (binom_good nB pB h).
rewrite bz - cprodA cprodC cprod0r =>h'.
by case: (factorial_nz nB).
Qed.

Lemma binom_monotone1 k n m:
  inc k Bnat -> inc n Bnat -> inc m Bnat ->
  k <> \0c -> k <=c (succ n) -> n <c m ->
  (binom n k) <c (binom m k).
Proof.
move: k n m.
have : forall k n, inc k Bnat -> inc n Bnat ->
  k <> \0c -> k <=c (succ n) -> (binom n k) <c (binom (succ n) k).
  move => k n kB nB r1 r2.
  move: (cpred_pr kB r1) => [pB ps].
  rewrite ps binomSnSm; fprops; rewrite -ps.
  apply: finite_sum4_lt; try apply: BS_binom;fprops.
  apply: binom_pr3 =>//.
  apply /(card_le_succ_succP (CS_Bnat pB) (CS_Bnat nB)); rewrite -ps//.
move=> aux k n m kB nB mB r1 r2 r3.
pose r p := (binom n k) <c (binom p k).
have sn: inc (succ n) Bnat by fprops.
have mi: inc m (interval_cc Bnat_order (succ n) m).
  apply /(Bint_ccP1 sn mB); split; fprops.
  apply /card_le_succ_lt0P; fprops.
apply: (cardinal_c_induction3_v (r:=r) sn mB) =>//.
  rewrite /r; apply: aux =>//.
move => n' /(Bint_coP1 sn mB) [r4 r5].
have r6: (binom n' k) <c (binom (succ n') k).
  apply: aux; fprops; first exact: (BS_lt_int r5 mB).
  have r7: k <=c n' by co_tac.
  exact:(card_leT r7 (card_le_succ0 (proj32 r7))).
rewrite /r; move => [r7 _]; co_tac.
Qed.

Lemma binom_monotone2 k n m:
  inc k Bnat -> inc n Bnat -> inc m Bnat ->
  k <> \0c -> k <=c (succ n) -> k <=c (succ m) ->
  (n <c m <-> (binom n k) <c (binom m k)).
Proof.
move=> kB nB mB r1 r2 r3.
split.
   apply: binom_monotone1 =>//.
case: (card_le_to_el (CS_Bnat mB) (CS_Bnat nB)) => //.
move=> mn [ble bne].
case: (equal_or_not n m) => nm.
  by rewrite nm in bne; case: bne.
have lmn : m <c n by split => //; apply: nesym.
have bgt: (binom m k) <c (binom n k) by apply: binom_monotone1 =>//.
co_tac.
Qed.

Lemma number_of_partitions_p3 E m p: inc m Bnat -> inc p Bnat ->
  cardinal E = m +c p ->
  cardinal (partitions_pi (variantLc m p) E) =
  binom (m +c p) m.
Proof.
move=> mB pB cE; move: (number_of_partitions_p2 mB pB cE); simpl.
set x:= cardinal _.
set n := factorial _.
set d := (factorial _) *c _.
move=> [p1 p2 p3 p4 p5].
have r1: m <=c (m +c p).
  by apply: csum_M0le; fprops.
have r2:((m +c p) -c m = p) by rewrite csumC; apply: cdiff_pr1; fprops.
rewrite cprodC in p2.
rewrite (cdivides_pr2 p3 p4 p1 p5 p2).
by rewrite (binom_pr1 (BS_sum mB pB) mB r1) r2.
Qed.

Lemma number_of_partitions_p4 E n m: inc n Bnat -> inc m Bnat ->
  cardinal E = n ->
  cardinal (partitions_pi (variantLc m (n -c m)) E) =
  binom n m.
Proof.
move=> nB mB cE.
case: (Bnat_to_el mB nB) => mn.
  move: (cdiff_pr0 nB mB mn) => [sB eql].
  rewrite -eql in cE.
  by rewrite (number_of_partitions_p3 mB sB cE) eql.
rewrite binom_bad // (cdiff_wrong (proj1 mn)).
set w := partitions_pi _ E; case: (emptyset_dichot w).
  move=> ->; apply: cardinal_set0.
move=> [t] /partitions_piP.
move=> pip; move: (pip_prop0 pip)=> aux.
move:pip=>[df cVg [fgf duj ue]].
have ad: inc C0 (domain (variantLc m \0c)) by bw; fprops.
move: (cVg _ ad); bw=> eq1.
have tA:inc C0 (domain t) by rewrite df; bw; fprops.
move: (sub_smaller (aux _ tA) ); rewrite eq1 cE => eq2.
co_tac.
Qed.

Definition subsets_with_p_elements p E:=
  Zo (powerset E)(fun z=> cardinal z =p).

Lemma subsets_with_p_elements_pr n p E: inc n Bnat -> inc p Bnat ->
  cardinal E = n ->
  binom n p = cardinal (subsets_with_p_elements p E).
Proof.
move=> nB pB cEn.
set src := partitions_pi (variantLc p (n -c p)) E.
set trg:= subsets_with_p_elements p E.
have cn: cardinalp n by fprops.
have cp: cardinalp p by fprops.
case: (card_le_to_el cp cn); last first.
  move=> np; rewrite binom_bad//.
  case: (emptyset_dichot trg).
     by move=> ->; rewrite cardinal_set0.
     move=> [y] /Zo_P [] /setP_P yE cy.
     move: (sub_smaller yE); rewrite cEn cy => pn; co_tac.
move=> pn.
move: (cdiff_pr0 nB pB pn) => [sB ps].
move: (cEn); rewrite -ps; move=> cEn'.
rewrite -(number_of_partitions_p3 pB sB cEn') -/src.
clear cEn'; apply /card_eqP.
exists (Lf (Vg ^~C0) src trg); split => //; aw.
apply: lf_bijective.
- move=> z /partitions_piP pip.
  have ta: inc C0 (domain z) by move: pip => [p1 _]; rewrite p1; bw; fprops.
  apply: Zo_i.
    by move: ((pip_prop0 pip) _ ta) => /setP_P.
  move: pip => [_ cp' _].
  move: cp'; bw =>cp'; rewrite (cp' _ inc_C0_2); bw.
- have aux: forall w, inc w src -> (Vg w C1 = E -s (Vg w C0)).
    move=> w /partitions_piP.
    move=>[df cVg [fgf duj ue]].
    have dgw: (domain w = C2) by rewrite df; bw.
    red in duj; rewrite dgw in duj.
    case: (duj _ _ inc_C0_2 inc_C1_2) => di1.
      by case: TP_ne.
    set_extens u; rewrite - ue.
      move => h1; apply /setC_P; split.
         union_tac; rewrite dgw; fprops.
      move=> h2; empty_tac1 u.
    move /setC_P=> [] /setUb_P [y]; rewrite dgw; case /C2_P => -> //.
  move=> u v us vs sWa.
  have sWb: Vg u C1 = Vg v C1 by rewrite (aux _ us) (aux _ vs) sWa.
  move: us vs => /partitions_piP [df cVg [fgf _ _]]
/partitions_piP [df' cV'[fgf' _ _]].
  apply: fgraph_exten =>//; first by rewrite df'.
  by rewrite df; bw;move=> x; case /C2_P => ->.
- move=> y /Zo_P [] /setP_P yE cyp.
  have aux:partition_w_fam (partition_with_complement E y) E.
   apply: is_partition_with_complement =>//.
  exists (variantLc y (E -s y)); bw.
  apply /partitions_piP; split => //; bw.
  move=> i itp; try_lvariant itp.
  rewrite (cardinal_setC4) ? cEn ? cyp //; apply /BnatP; ue.
Qed.

Lemma subsets_with_p_elements_pr0 n p: inc n Bnat -> inc p Bnat ->
  binom n p = cardinal (subsets_with_p_elements p n).
Proof.
move=> nB pB.
have cn: (cardinal n = n) by apply: card_card; fprops.
by rewrite (subsets_with_p_elements_pr nB pB cn).
Qed.

Lemma bijective_complement n p E: inc n Bnat -> inc p Bnat ->
  p <=c n -> cardinal E = n ->
  bijection (Lf (complement E)
    (subsets_with_p_elements p E)(subsets_with_p_elements (n -c p) E)).
Proof.
move=> nB pB pn cE.
apply: lf_bijective.
- move=> z /Zo_P [] /setP_P ze p1; apply: Zo_i.
   apply /setP_P;apply: sub_setC.
  rewrite cardinal_setC4 ?cE ?p1 //; apply /BnatP; ue.
- move => u v /Zo_P [] /setP_P h1 _ /Zo_P [] /setP_P h2 _.
  by rewrite -{2}(setC_K h1) -{2}(setC_K h2) => ->.
- move=> y /Zo_P [] /setP_P yE cy;exists (E -s y); last by rewrite (setC_K yE).
  apply: Zo_i.
    apply /setP_P; apply: sub_setC.
  have fse: finite_set E by apply /BnatP; ue.
  rewrite (cardinal_setC4 yE fse) cy cE; apply: double_diff => //.
Qed.

Definition functions_sum_eq E n:=
  Zo (functions E (Bintc n))
  (fun z=> (card_sum (P z)) = n).

Definition graphs_sum_eq F n:=
  fun_image (functions_sum_eq F n) graph.

Definition functions_sum_le E n:=
  Zo (functions E (Bintc n))
  (fun z=> (card_sum (P z)) <=c n).

Definition graphs_sum_le F n:=
  fun_image (functions_sum_le F n) graph.

Lemma setof_suml_auxP F n: inc n Bnat -> forall f,
  inc f (graphs_sum_le F n) <->
  [/\ domain f = F, (card_sum f) <=c n, fgraph f & cardinal_fam f].
Proof.
move=> nB f.
split.
  move=> /funI_P [z /Zo_P [/fun_set_P [ fz sz tz] cs] ->];split => //.
      rewrite - sz; aw.
     fprops.
  move=> i; rewrite -(proj33 fz) => iz.
  move: (Vf_target fz iz); rewrite tz => WB.
  move: (Bint_S WB); move=> h; fprops.
move=> [df sf fgf alc].
have tf: forall i, inc i F -> inc (Vg f i) (Bintcc \0c n).
  rewrite -df;move=> i iF.
  set (j := singleton i).
  have sjd: sub j (domain f) by move=> t /set1_P->.
  move: (alc _ iF) => aux.
  move: (csum_increasing1 alc sjd).
  have vr: Vg f i = Vg (restr f j) i by bw; rewrite /j; fprops.
  rewrite vr in aux.
  have dr: (domain (restr f j) = singleton i) by bw.
  rewrite (csum_trivial1 dr aux).
  rewrite -vr; move=> vle0.
  have vle: (Vg f i) <=c n by co_tac.
  apply /Bint_ccP1; fprops.
set z:= triple F (Bintc n) f.
apply /funI_P;exists z; rewrite /z => //; aw.
apply: Zo_i=> //; last by rewrite /triple; aw.
apply /fun_set_P;split => //; aw; apply: function_pr => //.
move=> t /(range_gP fgf) [x xs ->]; apply: tf; ue.
Qed.

Lemma setof_sume_auxP F n: inc n Bnat -> forall f,
  inc f (graphs_sum_eq F n) <->
  [/\ domain f = F, card_sum f = n, fgraph f& cardinal_fam f].
Proof.
move=> nB f; split.
  move=> /funI_P [z /Zo_P [/fun_set_P [ fz sz tz] cs] ->];split => //.
  - rewrite - sz; aw.
  - fprops.
  - move=> i; rewrite -(proj33 fz) => iz.
    by move: (Vf_target fz iz); rewrite tz => /Bint_S /CS_Bnat.
move=> [df sf fgf alc].
have : inc f (graphs_sum_le F n).
   apply /setof_suml_auxP => //; rewrite sf; split;fprops.
move => /funI_P [z /Zo_P [pa _] pb].
apply /funI_P; exists z=> //; apply: Zo_i => //; rewrite - sf pb; aw.
Qed.

Lemma sum_of_gen_binom E F n: inc n Bnat -> cardinal E = n ->
  card_sumb (graphs_sum_eq F n)
              (fun p => cardinal (partitions_pi p E))
  = (cardinal F) ^c n.
Proof.
move=> cE cEn.
have ->: ((cardinal F) ^c n = F ^c E).
  rewrite - cEn;apply: cpow_pr; fprops.
pose g f i:= (inv_image_by_fun f (singleton i)).
pose f1 f := (Lg F (fun i=> cardinal (g f i))).
pose f2 f := Lg F (g f).
have p1: forall f, inc f (functions E F) ->
     (inc (f1 f) (graphs_sum_eq F n)
      /\ inc (f2 f) (partitions_pi (f1 f) E)).
  move=> f /fun_set_P [ff sf tf].
  have sfa: (source f = unionb (Lg (target f) (g f))).
    set_extens t.
      move => tsf; apply /setUb_P; bw.
      move: (Vf_target ff tsf)=> Wt.
      ex_tac; bw; apply /iim_fun_set1_i => //.
    move => /setUb_P; bw; move => [y ytg]; bw => h.
    by move /(iim_fun_set1_P _ ff): h => [].
  have md: mutually_disjoint (Lg (target f) (g f)).
    apply: mutually_disjoint_prop2.
    move=> i j y itf jtf pa pb.
    by rewrite (iim_fun_set1_hi ff pa) (iim_fun_set1_hi ff pb).
  split; last first.
    rewrite /f1 /f2;apply /partitions_piP; red; bw;split => //.
       move => i iF; bw.
     red; rewrite -tf;split;fprops; ue.
  rewrite /f1; apply /(setof_sume_auxP _ cE);bw;split => //; last first.
    red; red; bw => i iF; bw; fprops.
   fprops.
  rewrite - cEn - sf sfa.
  apply /card_eqP; apply: equipotent_disjointU => //.
    rewrite /disjointU_fam; red;bw; split;fprops.
    move=> i itf; bw; [ eqtrans (cardinal (g f i)); eqsym; fprops | ue].
  apply: mutually_disjoint_prop2; bw => i j y pa pb; bw.
  by move /indexed_P => [_ _ <-] /indexed_P [_ _ <-].
set G:= Lg (graphs_sum_eq F n)
    (fun p => (Zo (functions E F) (fun f=> f1 f = p))).
have g1: unionb G = (functions E F).
  rewrite /G; set_extens f.
    by move /setUb_P ;bw; move => [y ys]; bw; move /Zo_P => [].
  move => fsf ;move: (p1 _ fsf) => [fa fb]; apply /setUb_P; bw.
  by ex_tac;bw; apply: Zo_i.
have g2: mutually_disjoint G.
  by apply: mutually_disjoint_prop2 => i j y ip jp /Zo_hi <- /Zo_hi <-.
symmetry; apply /card_eqP; rewrite -g1.
apply: equipotent_disjointU; fprops; rewrite /G/disjointU_fam; split; bw.
move=> i id; bw.
eqtrans (cardinal (partitions_pi i E)); eqtrans (partitions_pi i E).
set X:= Zo _ _.
exists (Lf f2 X (partitions_pi i E)); aw;split => //; aw.
apply: lf_bijective.
    by move=> t /Zo_P [ts <-]; move: (p1 _ ts) => [].
  move=> u v /Zo_P [] /fun_set_P [fu su tu] f1u
             /Zo_P [] /fun_set_P [fv sv tv] f1v Weq.
  apply: function_exten =>//; try ue.
  move=> x xsu /=.
  have WF: inc (Vf u x) F by Wtac.
  move: (f_equal (Vg ^~(Vf u x)) Weq); rewrite /f2 /g; bw => ieq.
  have : (inc x (inv_image_by_fun u (singleton (Vf u x)))).
     by apply: iim_fun_set1_i.
  by rewrite ieq; move /(iim_fun_set1_hi fv).
move=> y /partitions_piP ys.
move: (pip_prop0 ys)=> pip0.
move: ys=>[df cVg [fgf duj ue]].
have doi: domain i = F by move /(setof_sume_auxP _ cE): id => [].
rewrite doi in cVg.
set xf := fun x => choose (fun j => inc j F /\ inc x (Vg y j)).
have xfp: forall x, inc x E -> (inc (xf x) F /\ inc x (Vg y (xf x))).
  move=> x xE; apply choose_pr.
  move: xE;rewrite -ue => /setUb_P; rewrite df doi.
  by move => [z pa pb]; exists z.
have ta: lf_axiom xf E F by move=> t tE; case:(xfp _ tE).
set x:= Lf xf E F.
have fx: function x by apply: lf_function.
have xsf: inc x (functions E F) by apply /fun_set_P; rewrite /x;red;aw.
have xp1: forall t, inc t F -> g x t = Vg y t.
  move=> t tF; set_extens u.
    move /(iim_fun_set1_P _ fx) => []; rewrite lf_source => uE.
    rewrite /x;aw => -> ; apply : (proj2 (xfp _ uE)).
  move=> uW.
  have usx: inc u (source x).
    by rewrite -doi - df in tF; rewrite /x; aw; apply: (pip0 _ tF).
  apply:(iim_fun_set1_i fx usx).
  move: usx; rewrite /x lf_source => uE; aw.
  move: (xfp _ uE) => [vF tv].
  move: duj; rewrite /mutually_disjoint;aw; rewrite df doi.
  move=> aux; case: (aux _ _ tF vF) => // dj; empty_tac1 u.
have xp2: Lg F (g x) = y.
  symmetry; apply: fgraph_exten =>//; bw; fprops.
    rewrite df //.
  rewrite df doi; move => u uF /=; bw; rewrite - xp1 //.
exists x=>//; apply: Zo_i =>//.
move: id => /(setof_sume_auxP _ cE) [ pa pb pc pd].
apply: fgraph_exten; rewrite /f1; fprops; bw; first by symmetry.
move => a aF /=; bw; rewrite xp1 // cVg //.
Qed.

Lemma sum_of_gen_binom0 E n a:
  inc n Bnat -> cardinal E = n -> finite_int_fam a ->
  (card_sum a) ^c n =
     card_sumb (graphs_sum_eq (domain a) n)
       (fun p =>
         (cardinal (partitions_pi p E)) *c
            (card_prodb (domain a) (fun i=> ((Vg a i) ^c (Vg p i))))).
Proof.
move=> nB cEn fifa.
set F:=card_sum a; set I := domain a.
move: (finite_sum_finite fifa) => sB.
have cF: card_sum a = cardinal F .
  by symmetry; apply: card_card;apply: CS_Bnat.
move: (number_of_partitions1 fifa cF) => [pF].
move /partitions_piP => pipF.
have ->: (F ^c n = F ^c E).
  rewrite - cEn;apply: cpow_pr; fprops.
pose g f i := (inv_image_by_fun f (Vg pF i)).
pose f1 f := (Lg I (fun i=> cardinal (g f i))).
pose f2 f := Lg I (g f).
have g_propP: forall f i, inc f (functions E F) -> inc i I ->
    forall x , inc x (g f i) <-> (inc x E /\ inc (Vf f x) (Vg pF i)).
  move=> f i /fun_set_P [ff sf tf] iI x; rewrite - sf; split.
    rewrite /g; aw; move /iim_fun_P => [u pa pb].
    split; [ Wtac | rewrite - (Vf_pr ff pb) //].
  move => [pa pb]; apply /iim_fun_P; ex_tac; apply: Vf_pr3 =>//.
move: (pip_prop0 pipF) => prop0F.
move:pipF=>[da cVa [fga duja uea]].
have sfa: forall f, inc f (functions E F) -> unionb (Lg I (g f)) = E.
  move=> f fs; move: (fs) => /fun_set_P [ff sf tf].
  symmetry; rewrite - sf;set_extens t => ts.
    move: (Vf_target ff ts).
    rewrite tf -uea; move /setUb_P; rewrite da; move=> [y yda Vy].
    apply /setUb_P;exists y => //; bw; apply/ (g_propP _ _ fs yda).
    split=>//; ue.
  move /setUb_P: ts; bw; move => [y yI]; bw.
  by move /(g_propP _ _ fs yI) => []; rewrite sf.
have sfb: forall f, inc f (functions E F) ->
      mutually_disjoint (Lg I (g f)).
    move=> f fs;apply: mutually_disjoint_prop2.
    move=> i j y iI jI / (g_propP _ _ fs iI) [yE W1]/(g_propP _ _ fs jI) [_ W2].
    red in duja;move: duja;rewrite da; move=> h; case: (h _ _ iI jI)=>// h'.
    empty_tac1 (Vf f y).
have sfc:forall f, inc f (functions E F) ->
     inc (f2 f) (partitions_pi (f1 f) E).
  move=> f fs; rewrite /f1/f2;apply /partitions_piP; red; bw;split => //.
    move => i iF; bw.
  red; aw;split;fprops.
have sfd: forall f, inc f (functions E F) ->
    inc (f1 f) (graphs_sum_eq I n).
  move=> f fs ; apply /(setof_sume_auxP _ nB); rewrite /f1.
  rewrite - cEn -(sfa _ fs);split => //; bw; last first.
     red;red; bw; move => i itf; bw; fprops.
    fprops.
  apply /card_eqP;apply: equipotent_disjointU;fprops.
  split;fprops.
    rewrite /disjointU_fam; bw.
  rewrite /disjointU_fam; bw; move=> i itf; bw.
  eqtrans (cardinal (g f i)); eqsym; fprops.
set G:= Lg (graphs_sum_eq I n)
    (fun p => (Zo (functions E F) (fun f=> f1 f = p))).
have g1: unionb G = (functions E F).
  rewrite /G;set_extens f.
    by move /setUb_P; bw;move=> [y ys]; bw => /Zo_P [].
   move=> fsf;move: (sfd _ fsf) => fa; apply /setUb_P; bw; ex_tac; bw.
   by apply: Zo_i.
have g2: mutually_disjoint G.
  rewrite /G;apply: mutually_disjoint_prop2.
  by move=> i j y ip jp /Zo_hi <- /Zo_hi <-.
  rewrite /f1/partitions_pi /partition_with_pi_elements.
symmetry; apply /card_eqP; rewrite -g1.
apply: equipotent_disjointU; fprops.
rewrite /disjointU_fam Lg_domain.
red; bw;split; first by rewrite /G; bw.
move => p pd; bw.
set X:= (partitions_pi p E).
set Y := productb (Lg I (fun i=> (functions (Vg p i) (Vg pF i)))).
set aux:= _ *c _.
eqtrans aux; first by eqsym; fprops.
eqtrans (product X Y).
  rewrite /aux cprod2_pr1/card_prod; set t:= product _ _; eqtrans t.
  rewrite /t; clear t; apply: equipotent_setX; fprops.
  rewrite /card_prodb /card_prod.
  set t:= productb _ ; eqtrans t.
  rewrite /t; clear t; apply: equipotent_setXb; red;bw;split;fprops.
  move=> i iI; bw; fprops.
  eqtrans (cardinal (functions (Vg p i) (Vg pF i))).
  change (equipotent(card_pow (Vg a i) (Vg p i)) (card_pow (Vg pF i) (Vg p i))).
  have ->: (card_pow (Vg a i) (Vg p i) = card_pow (Vg pF i) (Vg p i)).
     apply: cpow_pr; fprops; rewrite - cVa //; fprops.
  fprops.
clear aux.
set (Z:= (Zo (functions E F) (fun f : Set => f1 f = p))).
have phi1: forall f, inc f Z -> inc (f2 f) X.
   move=> f /Zo_P [fs f1f];rewrite /X -f1f; apply: sfc =>//.
set WI:= fun f i => equipotent_ex (Vg p i) (g f i).
have W1: forall f i, inc f Z -> inc i I ->
  bijection_prop (WI f i) (Vg p i) (g f i).
  move=> f i fZ iI; rewrite /WI; apply: equipotent_ex_pr.
  move: fZ => /Zo_P [fa fb]; rewrite -fb; rewrite /f1; bw; fprops.
have W2: forall f f' i, inc f Z -> inc f' Z-> inc i I ->
    f2 f = f2 f' -> WI f i = WI f' i.
  move=> f f' i fZ f'Z iI sf1; rewrite /WI.
  by move: (f_equal (Vg ^~i) sf1); rewrite /f2; bw; move=> ->.
set WJ:= fun f i => (restriction2 f (g f i) (Vg pF i)) \co (WI f i).
have W3: forall f i, inc f Z -> inc i I ->
  [/\restriction2_axioms f (g f i) (Vg pF i) ,
   function (restriction2 f (g f i) (Vg pF i)) &
   (restriction2 f (g f i) (Vg pF i)) \coP (WI f i)].
  move=> f i fZ iI.
  move: (W1 _ _ fZ iI) => [bVf sVf tW].
  move: fZ=> /Zo_P [feF f1f].
  move :(g_propP _ _ feF iI) => g1P.
  move: feF => /fun_set_P [ff sf tf].
  have sgi: sub (g f i) (source f).
     by rewrite sf; move=> t /g1P; case.
  have ra:restriction2_axioms f (g f i) (Vg pF i).
    split => //.
      rewrite tf; apply: prop0F; ue.
    by move=> t /(Vf_image_P ff sgi) [u /g1P [uE pr] ->].
  have fr:function (restriction2 f (g f i) (Vg pF i)).
    apply: (proj31 (restriction2_prop ra)).
    by split => //; split => //; [ fct_tac | rewrite /restriction2;aw].
set f3:= fun f => (Lg I (WJ f)).
have phi2: forall f, inc f Z -> inc (f3 f) Y.
  rewrite /f3; move=> f fZ; apply /setXb_P; bw; split => //.
    fprops.
  move=> i iV; bw.
  move: (W3 _ _ fZ iV)(W1 _ _ fZ iV) => [p1 p2 p3][p4 p5 p6].
  rewrite /WJ; apply /fun_set_P.
  split => //;aw; [ fct_tac | rewrite /restriction2; aw].
eqsym.
exists (Lf (fun f =>(J (f2 f) (f3 f))) Z (X \times Y)).
red;aw;rewrite /G; bw; split => //;apply: lf_bijective.
   move=> f fZ; apply:setXp_i; fprops.
  move=> u v uZ vZ eq.
  move: (pr1_def eq)(pr2_def eq)=> sf2 sf3.
  move: (uZ) => /Zo_P [usf _].
  move: (uZ)(vZ) => /Zo_P [] /fun_set_P [fu su tu] f1u
                    /Zo_P [] /fun_set_P [fv sv tv] f1v.
  apply: function_exten =>//; try ue.
  rewrite su -(sfa _ usf); move=> x /setUb_P; bw; move => [i iI]; bw => xgui.
  move: sf3; rewrite /f3 => eq1.
  move: (f_equal (Vg ^~i) eq1); bw; rewrite /WJ => eq2.
  move:(W2 _ _ _ uZ vZ iI sf2) => eq3.
  move: (W3 _ _ uZ iI)(W1 _ _ uZ iI) => [p1 p2 p3][p4 p5 p6].
  move: (W3 _ _ vZ iI)(W1 _ _ vZ iI) => [p7 p8 p9][p10 p11 p12].
  rewrite -p6 in xgui.
  move: p4 => [_ sW]; move: ((proj2 sW) _ xgui) => [y ys vy].
  move: (f_equal (Vf ^~ y) eq2); aw; try ue.
  rewrite (restriction2_V p1); last by rewrite vy -p6.
  rewrite (restriction2_V p7); first by rewrite - eq3 vy //.
  Wtac; [ fct_tac |by rewrite p11 -p5 ].
move=> y /setX_P [py Py Qy].
move: (Py) => /partitions_piP [dy cVy pfay].
move: (pfay) =>[fgy dujy uey].
move: (Qy) => /Zo_P; bw; move=> [_ [fgQ dQ Qv]].
move /(setof_sume_auxP _ nB): (pd) => [fgp dp csp cVip].
set WK:= fun i => equipotent_ex (Vg p i) (Vg (P y) i).
have W4: forall i, inc i I ->
  (bijection_prop (WK i) (Vg p i) (Vg (P y) i)).
  move=> i iI; rewrite /WK; apply: equipotent_ex_pr; rewrite - cVy; fprops; ue.
pose hb i := (canonical_injection (Vg pF i) F) \co
  ((Vg (Q y) i) \co (inverse_fun (WK i))).
have Hv:forall i, inc i I ->
  [/\ (Vg (Q y) i) \coP (inverse_fun (WK i)),
   function ( (Vg (Q y) i) \co (inverse_fun (WK i)))
   & (canonical_injection (Vg pF i) F) \coP
  ((Vg (Q y) i) \co (inverse_fun (WK i)))].
  move=> i iI.
  move: (W4 _ iI)(Qv _ iI); bw; move => [bVf sw tW].
  move /fun_set_P => [fVg sVg tV].
  have p1: (Vg (Q y)i ) \coP (inverse_fun (WK i)).
    split => //; [ by apply: bijective_inv_f | aw; ue].
  have p2:function ((Vg (Q y) i) \co (inverse_fun (WK i))) by fct_tac.
  split => //;split => //.
    apply: ci_f; apply: prop0F; ue.
  by rewrite /canonical_injection; aw.
have Hw:forall i, inc i I -> function_prop (hb i) (Vg (P y) i) F.
  move=> i iI.
  move: (Hv _ iI) => [p1 p2 p3];rewrite /hb;red.
   rewrite compf_s compf_s compf_t.
  split; first (by fct_tac); last by rewrite /canonical_injection; aw.
  rewrite ifun_s; by move: (W4 _ iI); move => [bVf sw tW].
rewrite -fgp -dy in Hw.
move: (extension_partition1 pfay Hw).
set w := common_ext _ _ _;move => [[fw sw tw] alaw].
rewrite dy fgp in alaw.
have wsf:inc w (functions E F) by apply /fun_set_P.
have gp1: forall j x, inc j I -> inc x (Vg (P y) j) ->
    inc (Vf w x) (Vg pF j).
  move=> j x jI xV.
  move: (alaw _ jI) =>[p1 p2 p3]; rewrite (p3 _ xV).
  move: (Hv _ jI) => [p4 p5 p6].
  move: (W4 _ jI) (Qv _ jI);bw; move => [bWj sWj tWj].
  move /fun_set_P => [fVj sVj tVj].
  rewrite /hb; set aux := (Vg (Q y) j) \co _.
  have xsa: inc x (source aux) by rewrite /aux; aw; rewrite tWj.
  have xta: inc (Vf aux x) (Vg pF j).
       have <-:(target aux = Vg pF j) by rewrite /aux; aw.
       Wtac.
    aw; rewrite ci_V //; apply: prop0F; ue.
have gp2: forall i, inc i I -> g w i = Vg (P y) i.
  move => i iI; set_extens x.
     move /(g_propP _ _ wsf iI) => []; rewrite - uey; move /setUb_P.
     move=> [j]; rewrite dy fgp => jI xVj pa.
     move: (gp1 _ _ jI xVj) => Wp'.
     red in duja; rewrite da in duja; case: (duja _ _ iI jI) => h; try ue.
     empty_tac1 (Vf w x).
  move: (alaw _ iI)=> [p1 p2 p3] p4; apply /(g_propP _ _ wsf iI).
  split; first by rewrite - sw; apply: p1.
  by apply: gp1.
have wZ:inc w Z.
  apply: Zo_i => //.
  apply: fgraph_exten =>//;rewrite /f1; bw; fprops; try ue.
  move=> x xI /=; bw; rewrite gp2 //; apply: cVy; ue.
ex_tac.
have ->: (f2 w = P y).
  apply: fgraph_exten =>//;rewrite /f2; bw; fprops; try ue.
  move=> x xI /=; bw; rewrite gp2 =>//.
suff: (f3 w = Q y) by move=> ->; aw.
apply: fgraph_exten =>//;rewrite /f3; bw; fprops; try ue.
move => i iI; bw.
move: (W4 _ iI)(Qv _ iI); bw; move => [bVf sVf tW].
move => /fun_set_P [fVg sVg tV].
have ww: (WI w i = WK i) by rewrite /WI /WK gp2 //.
move: (W3 _ _ wZ iI); rewrite /WJ ww (gp2 _ iI); move => [ra rd cr].
apply: function_exten.
- apply: compf_f =>//; aw; ue.
- exact fVg.
- aw; ue.
- aw; rewrite /restriction2; aw; ue.
- have fW: function (WK i) by fct_tac.
aw; move=> x xs.
have p1:inc (Vf (WK i)x ) (target (WK i)) by Wtac.
move: (p1); rewrite tW => p11.
rewrite compf_V //restriction2_V //.
move: (alaw _ iI)=> [_ _ p3]; rewrite -tW in p3;rewrite (p3 _ p1).
rewrite /hb.
have p2: (Vg (Q y) i) \coP (inverse_fun (WK i)).
  split => //; [ by apply: bijective_inv_f | aw; ue].
have p0:function ((Vg (Q y) i) \co (inverse_fun (WK i))) by fct_tac.
rewrite da in prop0F; move: (@prop0F i iI)=> pf0.
have p4: (canonical_injection (Vg pF i) F) \coP
        ( (Vg (Q y) i) \co (inverse_fun (WK i))).
  split;fprops.
  by rewrite /canonical_injection; aw.
aw.
have <-: x = Vf (inverse_fun (WK i)) (Vf (WK i) x) by rewrite inverse_V2 =>//.
by rewrite ci_V // -tV //; Wtac; rewrite sVg - sVf.
Qed.

Lemma sum_of_gen_binom2 n: inc n Bnat ->
  card_sumb (Bintc n) (binom n) = \2c ^c n.
Proof.
move=> nB; symmetry.
have cnn:=(card_card (CS_Bnat nB)).
rewrite -(cardinal_set2 TP_ne) -/C2 - (sum_of_gen_binom C2 nB cnn).
set f:= fun m => (variantLc m (n -c m)).
have p1: forall m, inc m (Bintc n) ->
   inc (f m) (graphs_sum_eq C2 n).
  move=> m /Bintc_i mn.
  rewrite /f;apply /(setof_sume_auxP _ nB);split => //;bw.
      apply: (cdiff_pr mn).
    fprops.
  hnf; bw => i itp; try_lvariant itp; [ co_tac | fprops ].
rewrite /card_sumb (csum_Cn2 (I:=Bintc n) (f:= f));first last.
split => //; bw.
    rewrite /f;move=> u v ui vi s.
    move: (f_equal (Vg ^~C0) s); bw.
  move=> y / (setof_sume_auxP _ nB) [dy sy fgy alc].
  rewrite /cardinal_fam /allf dy in alc.
  move: (alc _ inc_C0_2) (alc _ inc_C1_2) => ca cb.
  have abn: (Vg y C0) +c (Vg y C1) = n.
     rewrite - sy; apply: csum2_pr.
     exists C0; exists C1; rewrite dy;split;fprops.
  move: (nB); rewrite -abn => nB'.
  move: (Bnat_in_sum2 ca nB')(Bnat_in_sum cb nB') => aB bB.
  move: (csum_M0le (Vg y C1) ca); rewrite abn => an.
  exists (Vg y C0); first by apply /BintcP.
  rewrite /f;apply: fgraph_exten; bw; fprops.
  rewrite dy;move=> x xtp; try_lvariant xtp.
  rewrite -abn csumC cdiff_pr1 //.
congr (card_sum _); apply: Lg_exten => x xi /=;bw; last by apply: p1.
by rewrite (number_of_partitions_p4 nB (@Bint_S \0c n _ xi) cnn).
Qed.

Lemma sum_of_binomial n: inc n Bnat ->
  card_sumb (Bintc n) (binom n) = \2c ^c n.
Proof.
move=> nB.
rewrite - card_setP.
set (idx:= Bintc n).
set (X:= Lg idx (fun p=>subsets_with_p_elements p n)).
set (Y:= disjointU_fam X).
have fgX: fgraph X by rewrite/ X; fprops.
have fgY: fgraph Y by rewrite /Y/disjointU_fam; fprops.
have dx: domain X = domain Y by rewrite /Y/disjointU_fam; bw.
have eqv: forall i, inc i (domain X) -> equipotent (Vg X i) (Vg Y i).
  move=> i idX; rewrite /Y/disjointU_fam; bw;fprops.
have mdX: mutually_disjoint X.
   apply: mutually_disjoint_prop2.
   move=> i j y id jd;rewrite / subsets_with_p_elements.
   by move=> /Zo_hi yi /Zo_hi yj; rewrite -yi -yj.
have mdY: mutually_disjoint Y by rewrite /Y; fprops.
move:(equipotent_disjointU (conj dx eqv) mdX mdY).
have ->:unionb X = powerset n.
  rewrite /X; set_extens t.
     by move /setUb_P; bw; move=> [y ydx]; bw; move /Zo_P => [].
  move => tp; apply /setUb_P; bw.
  have cxi: (inc (cardinal t) idx).
     apply /(BintcP nB); move: (tp) => /setP_P /sub_smaller.
     by rewrite (card_card (CS_Bnat nB)).
  by ex_tac; bw; apply: Zo_i.
move /card_eqP ->.
apply: csum_pr3; fprops; rewrite /X;bw => i ix; bw.
move: (@Bint_S \0c n _ ix) => iB.
rewrite - subsets_with_p_elements_pr0 //.
exact: (card_card (CS_Bnat (BS_binom nB iB))).
Qed.

Lemma sum_of_binomial2 a b n:
  cardinalp a -> cardinalp b -> inc n Bnat ->
  card_sumb (Bintc n)
         (fun p => (binom n p) *c (a ^c p) *c (b ^c (n -c p)))
  = (a +c b) ^c n.
Proof.
move=> ca cb nB.
move: n nB; apply: cardinal_c_induction.
  rewrite cpowx0 /card_sumb.
  set f := Lg _ _.
  have zi: inc \0c (Bintc \0c) by apply /BintcP; fprops.
  have df: domain f = singleton \0c by rewrite /f; bw; apply: Bint_cc00.
  have xo: Vg f \0c = \1c.
    rewrite /f; bw.
    rewrite cdiff_n_n // cpowx0 // cpowx0 // binom00; aw; fprops.
  rewrite (csum_trivial1 df) //; rewrite xo; fprops.
move=> n nB.
rewrite {1} /card_sumb; set fn := Lg _ _.
move=> hrec.
set X:=((a +c b) ^c n).
set I := (Bintc n).
have IB:sub I Bnat by apply: Bint_S.
pose q0 i := (a ^c i) *c (b ^c (n -c i)).
pose q1 i := (a ^c (succ i)) *c (b ^c ((succ n) -c (succ i))).
pose f1 i := (binom n (succ i)) *c (q1 i).
pose f2 i := (binom n i) *c (q1 i).
pose g1 i := (binom n i) *c (a ^c i) *c (b ^c ((succ n) -c i)).
have P1: card_sum (Lg I f2) = a *c X.
  pose g i:= a *c (binom n i) *c (q0 i).
  have ->: Lg I f2 = Lg I g.
    apply: Lg_exten.
    move=> x xi; rewrite /f2 /g (cprodC a _) - cprodA.
    congr (_ *c _); rewrite cprodC /q1 /q0.
    rewrite (cdiff_pr6 nB (IB _ xi)).
    rewrite (Bsucc_rw (IB _ xi)) cpow_sum2 cpowx1 //.
    rewrite - !cprodA; congr (_ *c _); apply: cprodC.
  symmetry;rewrite /X -hrec.
  rewrite (cprod2_sumDn a fn).
  rewrite /fn Lg_domain; congr (card_sum _); apply: Lg_exten.
  move=> x xI /=; bw.
  rewrite cprodA cprodA - cprodA //.
have P2: card_sum (Lg I g1) = b *c X.
  set (g:= fun i=> b *c ((binom n i) *c (q0 i))).
  have ->: Lg I g1 = Lg I g.
    apply: Lg_exten.
    move=> x xi /=; rewrite /g1/g (cprodC b _) - ! cprodA.
    have aux:= (Bsucc_rw (BS_diff x nB)).
    have h: succ (n -c x) +c x = succ n.
      move: xi => /(BintcP nB) /cdiff_pr => h.
      by rewrite aux csumC csumA h (Bsucc_rw nB).
    rewrite (cdiff_pr2 (BS_succ (BS_diff x nB)) (IB _ xi) h).
    rewrite aux cpow_sum2 cpowx1; fprops.
  symmetry;rewrite /X -hrec.
  rewrite (cprod2_sumDn b fn).
  rewrite /fn Lg_domain; congr (card_sum _); apply: Lg_exten.
  move=> x xI /=; bw; rewrite /g /q0.
  congr (_ *c _); symmetry; apply: cprodA.
clear hrec fn.
rewrite fct_sum_rec1//.
have sn: inc (succ n) Bnat by fprops.
have a1: cardinalp (card_pow b (succ n)) by rewrite /card_pow; fprops.
rewrite (binomSn0 nB) cpowx0 (cdiff_n_0 sn) (cprod1l CS1) (cprod1l a1).
set ffn:= fun i => _.
move: (sum_of_sums f1 f2 I); rewrite /card_sumb.
have ->:Lg I (fun i => (f1 i) +c (f2 i)) = (Lg I ffn).
  apply: Lg_exten => i iI.
  have iB: inc i Bnat by apply: IB.
  by rewrite /ffn -/(q1 i) /f1 /f2 (binomSnSm nB iB) - cprodA cprod_sumDr.
have g1z: (g1 \0c) = (b ^c (succ n)).
   rewrite /g1 cpowx0 (cdiff_n_0 sn) (binom0 nB).
   by rewrite (cprod1l CS1)(cprod1l (CS_pow b (succ n))).
rewrite -g1z => <-.
have {P1} ->: (card_sum (Lg I f2)) = a *c X by apply: P1.
rewrite (csumC _ (a *c X)) - csumA.
have cz:cardinalp (g1 \0c) by rewrite g1z /card_pow; fprops.
move: (fct_sum_rec1 g1 nB).
have P3: card_sum (Lg (Bintc (succ n)) g1)= b *c X.
  rewrite -P2 /I.
  have gp: (forall a, inc a Bnat -> cardinalp (g1 a)).
    move=> u uB; rewrite /g1; apply: CS_prod2.
  move: (induction_on_sum g1 sn) => /=.
  rewrite (Bint_co_cc sn) (Bint_co_cc nB) /card_sumb => <-.
  move: (card_lt_succ nB) => aux.
  have ->: (g1 (succ n) = \0c).
    by rewrite /g1 (binom_bad nB sn aux) - cprodA cprodC; apply: cprod0r.
  rewrite csum0r // /card_sum; fprops.
have p1: Lg I (fun i : Set => g1 (succ i)) = (Lg I f1).
  apply: Lg_exten; move=> u uI; rewrite /f1 /g1 - cprodA //.
rewrite /card_sumb -/I p1; move=> <-.
rewrite P3 - cprod_sumDr cprodC (Bsucc_rw nB) cpow_sum2 cpowx1; fprops.
Qed.


Definition functions_incr r r' :=
  (Zo (functions (substrate r) (substrate r'))
    (fun z => increasing_fun z r r')).
Definition functions_sincr r r' :=
  (Zo (functions (substrate r) (substrate r'))
    (fun z => strict_increasing_fun z r r')).

Lemma cardinal_set_of_increasing_functions1 r r' f:
  total_order r -> strict_increasing_fun f r r' ->
  (order_morphism f r r' /\ cardinal (substrate r) = cardinal (image_of_fun f)).
Proof.
move=> tor si.
move: (total_order_increasing_morphism tor si) => mor; split =>//.
move: (order_morphism_fi mor) => injf.
move: (restriction_to_image_fb injf)=> bj.
move: mor=> [_ _ [_ <- _] _ ].
apply /card_eqP; exists (restriction_to_image f).
split =>//; rewrite /restriction_to_image /restriction2; aw; split => //.
Qed.

Lemma cardinal_set_of_increasing_functions2 r r':
  total_order r -> total_order r' ->
  finite_set (substrate r) -> finite_set (substrate r') ->
  bijection (Lf (fun z => range (graph z))
     (functions_sincr r r')
    (subsets_with_p_elements (cardinal (substrate r)) (substrate r'))).
Proof.
move=> tor tor' fsr fsr'.
rewrite /functions_sincr.
set src:=Zo _ _.
set trg:= subsets_with_p_elements _ _.
set f:= Lf(fun z=> range (graph z)) src trg.
have ta: lf_axiom (fun z=> range (graph z)) src trg.
  move=> z /Zo_P [] /fun_set_P [fz sc tc] siz.
  move: (image_by_fun_source fz)=> imc.
  move:(cardinal_set_of_increasing_functions1 tor siz)=> [morz cs].
  apply /Zo_P; rewrite cs imc - tc;split => //; apply /setP_P.
  by apply: f_range_graph.
apply: lf_bijective =>//.
  move=> u v /Zo_P [] /fun_set_P [fu su tu] siu
    /Zo_P [] /fun_set_P [fv sv tv] siv sr.
  apply: function_exten =>//; [rewrite sv // | rewrite tv //|].
  move=> x xsu; ex_middle Wx.
  move: (finite_set_torder_wor tor fsr) => [or wor].
  set Z := Zo (substrate r) (fun x=> Vf u x <> Vf v x).
  have p1: sub Z (substrate r) by apply: Zo_S.
  have p2: nonempty Z by exists x; apply: Zo_i => //; ue.
  move: (wor _ p1 p2)=> [y []]; aw; move => p3 p4.
  move: p3 =>/Zo_P; rewrite - sv; move => [ysv Wy].
  have le: forall t, glt r t y -> Vf u t = Vf v t.
    move=> t ty; ex_middle Wt.
    have tZ: inc t Z by apply: Zo_i =>//; order_tac.
    move:(iorder_gle1 (p4 _ tZ)) => yt.
    order_tac.
  move: (order_morphism_fi(total_order_increasing_morphism tor siu)) => iu.
  move: (order_morphism_fi(total_order_increasing_morphism tor siv)) => iv.
  move: iu iv => [_ iu] [_ iv]; rewrite su - sv in iu.
  have: inc (Vf u y) (range (graph v)).
     rewrite - sr; Wtac; rewrite su - sv //.
  move /(range_fP fv) => [a asv Wa].
  have ya: glt r y a.
    move: (@total_order_pr2 r a y tor); rewrite - sv; move=> aux.
    case: (aux asv ysv) => h.
      rewrite - (le _ h) in Wa.
      by move: h; rewrite (iu _ _ ysv asv Wa); case.
    split =>//; move => h'; rewrite -h' in Wa; contradiction.
  have: inc (Vf v y) (range (graph u)) by rewrite sr; Wtac.
  move /(range_fP fu); rewrite su - sv; move=> [b bsv Wb].
  have yb: glt r y b.
    move: (@total_order_pr2 r b y tor); rewrite - sv; move=> aux.
    case: (aux bsv ysv) => h.
      rewrite (le _ h) in Wb.
      by move: h; rewrite (iv _ _ ysv bsv Wb); case.
      split =>//; move => h'; rewrite -h' in Wb; by case: Wy.
  move: siv =>[_ _ _ siv]; move: (siv _ _ ya); rewrite -Wa => h1.
  move: siu =>[_ w _ siu]; move: (siu _ _ yb); rewrite -Wb; move => h2.
  order_tac.
have or':order r' by move: tor' => [tor' _].
move=> y /Zo_P [] /setP_P ys /card_eqP ey.
move: (total_order_sub tor' ys).
set (r'' := induced_order r' y).
move=> tor''.
have sr'': (substrate r'' = y) by rewrite /r''; aw.
have e1: ( (substrate r) \Eq (substrate r'')) by rewrite sr''; eqsym.
move: (isomorphism_worder_finite tor tor'' fsr e1) => [g [gi _]].
move: (gi)=> [_ _ [bg sg tg] ig].
have cc: ((canonical_injection y (substrate r')) \coP g).
  split => // ; [fprops | fct_tac | rewrite / canonical_injection - sr''; aw].
  done.
set (x:= (canonical_injection y (substrate r')) \co g).
have fg: (function x) by rewrite /x; fct_tac.
have sx: (source x = substrate r) by rewrite /x - sg; aw.
have tx: target x = substrate r' by rewrite /x/canonical_injection; aw.
have gp: forall a, inc a (source g) -> inc (Vf g a) y.
   rewrite - sr'' - tg; move=> a asg; Wtac; fct_tac.
have xp: forall a, inc a (source g) -> Vf x a = Vf g a.
   move=> a ag; rewrite /x; aw; rewrite ci_V //; apply: gp=>//.
have gxp: forall a, inc a (source g) -> inc (Vf x a) y.
   move=> a ax; rewrite xp //; apply: gp=>//.
move: bg => [[fcg ing] sug].
have xsr: inc x src.
  rewrite /src; apply: Zo_i => //; first by apply /fun_set_P.
  split => //; first by move: tor=> [tor _].
  move=> a b [ab nab].
  have asx: (inc a (source g)) by rewrite sg; order_tac.
  have bsx: (inc b (source g)) by rewrite sg; order_tac.
  rewrite (xp _ asx) (xp _ bsx).
  move: ab;rewrite (ig _ _ asx bsx) /r'' => h.
  split; [exact: (iorder_gle1 h) | dneg nW; apply: ing =>// ].
ex_tac.
set_extens t.
  rewrite - sr'' - tg=> tt; move: ((proj2 sug) _ tt)=> [a asx av].
  apply /(range_fP fg); rewrite sx - sg -av -(xp _ asx); ex_tac.
move /(range_fP fg) => [u].
rewrite sx - sg => us tw; rewrite tw; apply: gxp =>//.
Qed.

Lemma cardinal_set_of_increasing_functions r r':
  total_order r -> total_order r' ->
  finite_set (substrate r) -> finite_set (substrate r') ->
  cardinal (functions_sincr r r')
  = binom (cardinal (substrate r')) (cardinal (substrate r)).
Proof.
move=> tor tor' fsr fsr'.
move: (cardinal_set_of_increasing_functions2 tor tor' fsr fsr').
set src := functions_sincr r r'.
set trg := subsets_with_p_elements _ _.
move=> h.
have -> :cardinal src = cardinal trg.
  apply /card_eqP.
  exists (Lf (fun z : Set => range (graph z)) src trg); split => //; aw.
rewrite /trg.
symmetry;set n := cardinal _; set p := cardinal _.
have nB: inc n Bnat by apply /BnatP; apply: fsr'.
have pB: inc p Bnat by apply /BnatP; apply: fsr.
have cE: cardinal (substrate r') = n by [].
by rewrite (subsets_with_p_elements_pr nB pB cE).
Qed.

Lemma increasing_prop0 p f r: inc p Bnat -> order r ->
  (forall i, i <=c p -> inc (f i) (substrate r)) ->
  (forall n, n <c p -> gle r (f n) (f (succ n))) ->
  (forall i j, i <=c j -> j <=c p ->
    gle r (f i) (f j)).
Proof.
move=> pB or als hyp i j ij jp.
have jB: inc j Bnat by Bnat_tac.
have iB: inc i Bnat by Bnat_tac.
move:(cdiff_pr0 jB iB ij).
set k := (j -c i); move=> [kB ikj]; rewrite -ikj.
have ckk: k <=c k by fprops.
set (pr:= fun n => (n <=c k) -> gle r (f i) (f (i +c n))).
apply: (cardinal_c_induction (r:= pr)) =>//.
  move=> aux; aw; [ order_tac; apply: als; co_tac | fprops ].
move => n nB prn h.
have le2: n <c (succ n) by bw; fprops.
have le4: (i +c n) <c p.
  have le3: n <c k by co_tac.
  move: (csum_Mlteq iB kB le3).
  rewrite csumC (csumC k i) ikj => le4; co_tac.
move: (hyp _ le4).
have -> : (succ (i +c n) = (i +c (succ n))) by rewrite - csum_via_succ //.
move=> r1;move: le2 => [le2 _].
have le3: n <=c k by co_tac.
move: (prn le3) => r2; order_tac.
Qed.

Lemma strict_increasing_prop0 p f r: inc p Bnat -> order r ->
  (forall n, n <c p -> glt r (f n) (f (succ n))) ->
  (forall i j, i <c j -> j <=c p ->
    glt r (f i) (f j)).
Proof.
move=> pB or hyp i j ij jp.
have jB: inc j Bnat by Bnat_tac.
have iB: inc i Bnat by move: ij => [ij _ ];Bnat_tac.
have ip: i <c p by co_tac.
move: ij; move /(card_le_succ_ltP _ iB) => ij.
have siB: inc (succ i) Bnat by fprops.
move:(cdiff_pr0 jB siB ij).
set k := (j -c (succ i)); move=> [kB ikj]; rewrite -ikj.
have ckk: k <=c k by fprops.
set pr:= fun n => (n <=c k) -> glt r (f i) (f ((succ i) +c n)).
apply: (cardinal_c_induction (r:= pr)) =>//.
  move=> aux; aw; [ apply: hyp =>// | fprops].
move => n nB prn h.
set m := succ (i +c n).
have mv: m = ((succ i) +c n).
  rewrite csumC /m csumC csum_via_succ//.
have <-: (succ m = (succ i) +c (succ n)).
   rewrite mv (Bsucc_rw iB) (Bsucc_rw nB) csumA.
   move: BS1 => b1; rewrite Bsucc_rw //; fprops.
have le2: n <c (succ n) by bw; fprops.
have ltkn: n <c k by co_tac.
have mp: m <c p.
  move: (csum_Mlteq siB kB ltkn);rewrite csumC -mv csumC ikj => hh; co_tac.
move: (hyp _ mp) => r1.
move: ltkn => [ltkn _];move: (prn ltkn).
rewrite -mv; move => [r2 _]; order_tac.
Qed.

Lemma increasing_prop p f r: inc p Bnat -> function f ->
  source f = Bint (succ p) -> order r -> substrate r = target f ->
  (forall n, n <c p -> gle r (Vf f n) (Vf f (succ n))) ->
  increasing_fun f (Bint_cco \0c p) r.
Proof.
move=> pB ff sf or sr sge.
have zB: inc \0c Bnat by fprops.
have bi:Bintc p = source f by rewrite sf; apply: Bint_co_cc =>//.
move: (Binto_wor \0c p) => [pa pb].
move: (worder_total pa) => [sor _ ].
split => //.
  by rewrite pb.
move=> x y /Binto_gleP [xs ys lxy].
move: ys => /(BintcP pB) yp.
have aux: (forall i, i <=c p -> inc (Vf f i) (substrate r)).
  by move=> i ip; Wtac; rewrite sf; apply /BintsP.
exact: (increasing_prop0 pB or aux sge lxy yp).
Qed.

Lemma strict_increasing_prop p f r: inc p Bnat -> function f ->
  source f = Bint (succ p) -> order r -> substrate r = target f ->
  (forall n, n <c p -> glt r (Vf f n) (Vf f (succ n))) ->
  (injection f /\
    strict_increasing_fun f (Bint_cco \0c p) r).
Proof.
move => pB ff sf or sr prop.
have zB: inc \0c Bnat by fprops.
have bi:Bintc p = source f by rewrite sf; apply: Bint_co_cc =>//.
move: (Binto_wor \0c p) => [pa pb].
move: (worder_total pa) => tor.
have sic: (strict_increasing_fun f (Bint_cco \0c p) r).
  split => //.
      by move: tor => [sor _].
    by rewrite pb.
    move=> x y [] /Binto_gleP [xs ys lxy] xne.
    move: ys => /(BintcP pB) yp.
    have ltxy: x <c y by split.
    apply: (strict_increasing_prop0 pB or prop ltxy yp).
split=>//.
move: (total_order_increasing_morphism tor sic).
apply: order_morphism_fi.
Qed.

Lemma strict_increasing_prop1 f p:
  inc p Bnat -> (forall i, i <c p -> inc (f i) Bnat)
  -> (forall i j, i <c j -> j <c p -> (f i) <c (f j)) ->
  (forall i, i <c p -> i <=c (f i)).
Proof.
move=> pB ali hi i lip.
have iB: (inc i Bnat) by move: lip=> [leip _]; Bnat_tac.
move: i iB lip; apply: cardinal_c_induction.
  move=> aux;apply: czero_least.
  move: (ali _ aux); fprops.
move=> n nB pn aux.
have le2:=(card_lt_succ nB).
have le3:=(hi _ _ le2 aux).
have le4:= (pn (card_lt_ltT le2 aux)).
apply /card_le_succ_lt0P; [ co_tac | fprops | co_tac ].
Qed.

Lemma increasing_prop1 p f: inc p Bnat ->
  (forall i, i <=c p -> inc (f i) Bnat) ->
  (forall n, n <c p -> (f n) <=c (f (succ n))) ->
  (forall i j, i <=c j -> j <=c p -> (f i) <=c (f j)).
Proof.
move => pB p1 p2 i j ij jp.
move: (Bnat_order_wor) => [[or _] sr].
set r := Bnat_order.
have q1: (forall i, i <=c p -> inc (f i) (substrate r)).
  by rewrite sr.
have q2:(forall n, n <c p -> gle r (f n) (f (succ n))).
  move=> n np; apply/ Bnat_order_leP; split;fprops.
    by apply: p1; move: np => [np _].
  apply: p1; apply /card_le_succ_lt0P => //; fprops.
  by move: np=> [[cn _] _].
move: (increasing_prop0 pB or q1 q2 ij jp).
by move /Bnat_order_leP => [_ _].
Qed.

Lemma strict_increasing_prop2 f p:
  inc p Bnat -> (forall i, i <c p -> inc (f i) Bnat)
  -> (forall i j, i <c j -> j <c p -> (f i) <c (f j)) ->
  (forall i j, i <=c j -> j <c p -> ((f i) -c i) <=c ((f j) -c j)).
Proof.
move=> pB ali hyp.
case: (equal_or_not p \0c).
  move => -> i j ij jp; case: (card_lt0 jp).
move=> pnz.
move:(cpred_pr pB pnz) => [qB ps].
set q := cpred p.
have fq: finite_c (cpred p) by fprops.
set (g:= fun i=> ((f i) -c i)).
have q1: (forall i : Set, i <=c q -> inc (g i) Bnat).
  move=> i ip;
  have iB: inc i Bnat by Bnat_tac.
  rewrite /g; apply: BS_diff =>//.
  by apply: ali; rewrite ps //; apply /card_lt_succ_leP.
have q2:forall n : Set, n <c q -> (g n) <=c (g (succ n)).
  move=> n np.
  have nB: inc n Bnat by move: np => [np _]; Bnat_tac.
  have nsB: inc (succ n) Bnat by fprops.
  rewrite /g.
  move:(strict_increasing_prop1 pB ali hyp) => hy.
  have p1: (succ n) <c p.
   rewrite ps ; apply /(card_lt_succ_leP qB) /card_le_succ_lt0P=> //; fprops.
  have p2: n <c p.
     move: (card_le_succ nB)=> aux.
     co_tac.
  move: (hy _ p1) (hy _ p2)=> qp1 qp2.
  move: (ali _ p1)(ali _ p2) => s1 s2.
  move:(cdiff_pr0 s1 nsB qp1)(cdiff_pr0 s2 nB qp2).
  set a:= (f (succ n)) -c (succ n).
  set b := ((f n) -c n).
  move=> [aB r1][bB r2].
  have nsn: n <c (succ n) by fprops.
  move: (hyp _ _ nsn p1);rewrite -r1 -r2.
  have->: ((succ n) +c a = succ (n +c a)).
    by rewrite csumC (csum_via_succ _ nB) csumC.
  move /(card_lt_succ_leP (BS_sum nB aB)); apply: csum_le_simplifiable =>//.
move=> i j ij jp.
apply: (increasing_prop1 qB q1 q2 ij).
by move: jp; rewrite {1} ps; move /(card_lt_succ_leP qB).
Qed.

Lemma strict_increasing_prop3 f p n:
  inc p Bnat -> inc n Bnat -> (forall i, i <c p -> inc (f i) Bnat)
  -> (forall i j, i <c j -> j <c p -> (f i) <c (f j)) ->
  (forall i, i <c p -> (f i) <c (n +c p)) ->
  (forall i, i <c p -> ((f i) -c i) <=c n).
Proof.
move=> pB nB ali fi fb.
move=> i ip.
case: (equal_or_not p \0c) => h.
  rewrite h in ip;case: (card_lt0 ip).
move: (cpred_pr pB h) => [qB psq].
move:ip; rewrite psq; move /(card_lt_succ_leP qB)=> iq.
have qp: ((cpred p) <c p) by rewrite {2} psq; bw; fprops.
apply: (@card_leT _ ((f (cpred p)) -c (cpred p))).
  by move: (strict_increasing_prop2 pB ali fi iq qp).
move: (strict_increasing_prop1 pB ali fi qp) => aa.
have fB: (inc (f (cpred p)) Bnat) by apply: ali =>//.
move: (cdiff_pr aa) => csp.
move: (fb _ qp); rewrite - csp.
set (r:= ((f (cpred p)) -c (cpred p))).
have rB: inc r Bnat by rewrite /r;fprops.
have ->: (n +c p = succ ( (cpred p) +c n)).
  by rewrite {1} psq (csum_via_succ _ qB) csumC.
move=> hh.
have sB: inc ((cpred p) +c n) Bnat by fprops.
apply: (@csum_le_simplifiable (cpred p)); fprops.
rewrite cdiff_pr //; first by move /(card_lt_succ_leP sB): hh.
apply: csum_M0le; fprops.
Qed.

Lemma cardinal_set_of_increasing_functions3 n p:
  inc n Bnat -> inc p Bnat ->
  cardinal (functions_incr (Bint_co p)
         (Bint_cco \0c n))
   = binom (n +c p) p.
Proof.
move=> nB pB.
set r := (Bint_co p).
set r' := (Bint_cco \0c n).
set (E1:=Bint p).
have s1: E1= substrate r by rewrite /E1 (proj2 (Bintco_wor _)).
set E2:=Bintc n.
have s2: (E2= substrate r') by rewrite /E2 (proj2 (Binto_wor _ _)); fprops.
set np := n +c p.
have npB: inc np Bnat by rewrite /np; fprops.
set (r'':= Bint_co np).
set (E3:=Bint np).
have s3: E3= substrate r'' by rewrite /E3 - (proj2 (Bintco_wor _)).
set Q1:= functions_incr r r'.
set Q2:= functions_sincr r r''.
set (P1:= fun x => function_prop x E1 E2 /\ increasing_fun x r r').
set (P2:= fun x => function_prop x E1 E3 /\ strict_increasing_fun x r r'').
have HQ1P: forall x, inc x Q1 <-> P1 x.
  move=> x; rewrite /Q1 /P1 s1 s2; split.
      by move => /Zo_P [] /fun_set_P pa pd.
      by move => [pa pb]; apply: Zo_i => //; apply /fun_set_P.
have HQ2P: forall x, inc x Q2 <-> P2 x.
  move=> x; rewrite /Q2 /P2 s1 s3; split.
      by move => /Zo_P [] /fun_set_P pa pd.
      by move => [pa pd]; apply: Zo_i => //; apply /fun_set_P.
have E1B :sub E1 Bnat by rewrite /E1; apply: Bint_S1.
have E2B :sub E2 Bnat by rewrite /E2; apply: Bint_S.
have E3B :sub E3 Bnat by rewrite /E3; apply: Bint_S1.
set (subi:= fun f => Lf (fun i=> (Vf f i) -c i) E1 E2).
have Hi0:forall f, inc f Q2 ->
   [/\ (forall i, i <c p -> inc (Vf f i) Bnat),
    (forall i j, i <c j -> j <c p -> (Vf f i) <c (Vf f j)) &
    (forall i, inc i E1 -> (i <=c (Vf f i)))].
  move=> f /HQ2P [[ff sf tf] sif].
  have aux: (forall i, i <c p -> inc (Vf f i) Bnat).
    by move=> i ilp; apply: E3B =>//; Wtac; rewrite sf /E1; apply/BintP.
  have aux2:(forall i j, i <c j -> j <c p -> (Vf f i) <c (Vf f j)).
    move=> i j ij jp.
    move: (ij) => [ij1 _].
    have isf: (inc i (source f))by rewrite sf /E1;apply/BintP =>//;co_tac.
    have jsf: (inc j (source f))by rewrite sf /E1;apply/BintP =>//;co_tac.
    have lij: glt r i j.
       move: ij => [ij nij]; rewrite /r; split=>//.
       apply / Bintco_gleP => //.
    move: sif => [ _ _ _ h]; move: (h _ _ lij) => [lVf nW].
    by split =>//; move: lVf; move /(Bintco_gleP npB) => [].
  split => //.
  move=> i /(BintP pB) h.
  by apply: (strict_increasing_prop1 pB aux aux2).
have Hi3:forall f, inc f Q2 ->
    lf_axiom (fun i => (Vf f i) -c i) E1 E2.
  move=> f fQ2; move: (Hi0 _ fQ2) => [p1 p2 p3].
  move: (strict_increasing_prop2 pB p1 p2) => p4.
  have p5: (forall i, i <c p-> (Vf f i) <c (n +c p)).
    move=> i ip.
    move: fQ2 => / HQ2P [[ff sf tf] vf].
    have : (inc (Vf f i) E3).
      by rewrite -tf; Wtac; rewrite sf;apply/ (BintP pB).
    by move /(BintP npB).
  move: (strict_increasing_prop3 pB nB p1 p2 p5) => p6.
  by move=> i /(BintP pB) => ip; apply /(BintcP nB);apply: p6.
have Hi1:forall f, inc f Q2 -> inc (subi f) (functions E1 E2).
   move=> f fQ2;apply /fun_set_P; rewrite /subi; red;aw;split => //.
   by apply: lf_function; apply: Hi3.
have Hi2:forall f, inc f Q2 -> inc (subi f) Q1.
  move=> f fQ2; apply: Zo_i; first by rewrite - s1 - s2; apply: Hi1.
  move: (Hi3 _ fQ2) => ta.
  move: (Bintco_wor p) => [[or _] _].
  move: (Binto_wor \0c n) => [[or' _] _].
  rewrite /subi;red; aw; split => //; first (split; aw).
    by apply: lf_function.
  move=> x y xy.
  have xsf: (inc x E1) by rewrite s1; order_tac.
  have ysf: (inc y E1) by rewrite s1; order_tac.
  move: (Hi0 _ fQ2) => [p1 p2 p3].
  move:(strict_increasing_prop2 pB p1 p2) => p4.
  have yp: y <c p by move: ysf; move /(BintP pB).
  have xy': x <=c y by move: xy => /(Bintco_gleP pB) [].
  by move: (p4 _ _ xy' yp); aw => xx; apply /Binto_gleP; split => //;apply: ta.
set (G:= Lf (fun f=> subi f) Q2 Q1).
have Hi4:function G by rewrite / G; apply: lf_function.
set (addi:= fun f => Lf (fun i=> (Vf f i) +c i) E1 E3).
have pa:forall f, inc f (functions E1 E2) ->
    lf_axiom (fun i => (Vf f i) +c i) E1 E3.
  move=> f /fun_set_P [ff sf tf] t tE1.
  have: (inc (Vf f t) E2) by Wtac.
  move: tE1 => /(BintP pB) p1 /(BintcP nB) p2.
  apply /(BintP npB); apply: csum_Mlelt =>//; Bnat_tac.
have pa2: (forall f, inc f (functions E1 E2) ->
    inc (addi f) (functions E1 E3)).
  move=> f fE; rewrite /addi; apply /fun_set_P;red;aw;split => //.
  by apply: lf_function; apply: pa.
have pa3: forall f, inc f Q1 -> inc (addi f) Q2.
  move=> f /Zo_P; rewrite - s1 - s2; move=>[fe1e2 incf].
  apply /HQ2P; move: (pa2 _ fe1e2) => /fun_set_P [fa sa ta]; split => //.
  red; rewrite /function_prop sa ta; split => //.
      by move: (Bintco_wor p) => [[or _] _].
    by move: (Bintco_wor np) => [[or _] _].
  move=> x y [xy nxy].
  have xe1: inc x E1 by rewrite s1; order_tac.
  have ye1: inc y E1 by rewrite s1; order_tac.
  move: (pa _ fe1e2) => ta1.
  rewrite /addi lf_V // lf_V //.
  move: incf => [_ _ _ h]; move: (h _ _ xy); rewrite /r'/r'' /glt.
  have zB: inc \0c Bnat by fprops.
  move /Binto_gleP => [p1 p2 p3].
  have ltxy: x <c y.
    by split =>//; move: xy; move /(Bintco_gleP pB) => [].
  move: p1 => /(BintcP nB) => p1.
  move: p2 => /(BintcP nB) => p2.
  have: ( (Vf f x) +c x) <c ( (Vf f y) +c y).
     apply: csum_Mlelt =>//; try Bnat_tac; try apply: E1B =>//.
  move=> [p4 p5];split => //; apply /(Bintco_gleP npB); split => //.
   apply: csum_Mlelt => //.
  by move: ye1 => /(BintP pB).
set (F:= Lf (fun f=> (addi f)) Q1 Q2).
have ff: function F by rewrite /F;apply: lf_function.
have cGF: composable G F by rewrite /G/F; split => //; aw.
have cFG: composable F G by rewrite /G/F; split => //; aw.
have c1i: (compose G F = identity (source F)).
  apply: function_exten; aw; [fct_tac |apply: identity_f | | ].
     rewrite /G/F; aw.
  move => x xsf /=;rewrite identity_V //.
  move: xsf ;rewrite /F; rewrite {1} corresp_s => xQ1.
  have aQ2: inc (addi x) Q2 by apply: pa3.
  aw; rewrite /G; aw.
  rewrite /addi/subi.
  move: (xQ1) => /HQ1P [[fx sx tx] icx].
  apply: function_exten; aw =>//.
     apply: lf_function; apply: Hi3; apply: pa3 =>//.
  move: (Hi3 _ aQ2)=> ta2.
  move=> a aE1 /=; aw.
    apply: cdiff_pr1; last by apply: E1B.
    apply: E2B;rewrite -tx//; Wtac.
  apply: pa; apply /fun_set_P;split => //.
have c2i: (compose F G = identity (source G)).
  apply: function_exten.
  - fct_tac.
  - apply: identity_f.
  - rewrite /F/G; aw.
  - rewrite /F/G;aw.
  - rewrite /G; aw.
  - move=> x xQ2 /=;rewrite identity_V //.
    have qQ1: inc (subi x) Q1 by apply: Hi2.
    move: (xQ2) => /HQ2P [[fx sx tx] icx].
    aw;rewrite /F; aw; rewrite /addi/subi.
    apply: function_exten =>//.
    - apply: lf_function; apply: pa; apply: Hi1=> //.
    - symmetry;aw.
    - symmetry; aw.
    - move: (Hi3 _ xQ2) => ta3.
      move:(pa _ (Hi1 _ xQ2)) => ta2.
      aw; move => a aE1 /=; aw; apply: cdiff_rpr.
      by move: (proj33 (Hi0 _ xQ2)); apply.
move: (bijective_from_compose cGF cFG c1i c2i) =>[bF bG GF].
have : (equipotent Q1 Q2) by exists F; rewrite /F;split => //; aw .
move /card_eqP; move=> ->.
have r1: (cardinal (substrate (Bint_co np))) = np.
   by rewrite (proj2 (Bintco_wor _)) card_Bint.
have r2: (cardinal (substrate (Bint_co p))) = p.
  by rewrite (proj2 (Bintco_wor _)) card_Bint.
rewrite /Q2 /r/r'' cardinal_set_of_increasing_functions /finite_set.
- rewrite r1 r2 //.
- apply: worder_total; apply: (proj1 (Bintco_wor _)).
- apply: worder_total; apply: (proj1 (Bintco_wor _)).
- by rewrite r2; fprops.
- by rewrite r1; fprops.
Qed.

Lemma increasing_compose f g r r' r'':
  increasing_fun f r r' -> increasing_fun g r' r'' ->
  [/\ g \coP f,
    (forall x, inc x (source f) -> Vf (g \co f) x = Vf g (Vf f x))
    & increasing_fun (g \co f) r r''].
Proof.
move=> [or or' [ff sf tf] icf][_ or'' [fg sg tg] icg].
have cgf: ( g \coP f) by split => //; ue.
have p:(forall x, inc x (source f) -> Vf (g \co f) x = Vf g (Vf f x)).
  move=> x xsf; aw.
split => //; split => //; first by split;aw; fct_tac.
move => x y xy.
   have xsf: inc x (source f) by rewrite sf; order_tac.
   have ysf: inc y (source f) by rewrite sf; order_tac.
by rewrite p // p //; apply: icg; apply: icf.
Qed.

Lemma increasing_compose3 f g h r r' r'' r''':
  strict_increasing_fun f r r' -> increasing_fun g r' r'' ->
  strict_increasing_fun h r'' r''' ->
  let res:= (h \co g) \co f in
    [/\ inc res (functions (source f) (target h)),
      (forall x, inc x (source f) -> Vf res x = Vf h (Vf g(Vf f x))) &
      increasing_fun res r r'''].
Proof.
move=> sif ig sih.
move: (strict_increasing_w sif) => icf.
move: (strict_increasing_w sih) => ich.
move: (increasing_compose ig ich)=> [chg Whg igh].
move: (increasing_compose icf igh)=> [chgf Whgf ighf].
move=> res; rewrite /res;split => //.
  apply /fun_set_P; split => //; aw; fct_tac.
move=> x xsf; aw.
move: (increasing_compose icf ig) => [[_ ff sgtf] _ _];Wtac.
Qed.

Lemma cardinal_set_of_increasing_functions4 r r':
  let n := (cardinal (substrate r')) in
    let p := (cardinal (substrate r)) in
      total_order r -> total_order r' ->
      finite_set (substrate r) -> finite_set (substrate r') ->
      cardinal (functions_incr r r')
      = binom ((n +c p) -c \1c) p.
Proof.
move=> n p tor tor' fsr fsr'.
have nB: inc n Bnat by move: fsr' => /BnatP.
have pB: inc p Bnat by move: fsr => /BnatP.
have or: order r by move: tor => [tor _ ].
have or': order r' by move: tor' => [tor' _ ].
case: (equal_or_not n \0c) => nz.
  rewrite nz; aw; fprops.
  have qe: substrate r'= emptyset by apply: cardinal_nonemptyset; rewrite-nz//.
  rewrite /functions_incr qe.
  case: (equal_or_not p \0c) => pz.
    rewrite pz cdiff_wrong;fprops.
    rewrite binom00.
    have qe': substrate r = emptyset.
      by apply: cardinal_nonemptyset; rewrite -pz//.
    rewrite qe'; set qq:=Zo _ _.
    suff: singletonp qq by move => [x ->]; rewrite cardinal_set1.
    apply /singletonP; split.
       exists empty_function.
       move:empty_function_function => xx.
       apply : Zo_i; first by apply /fun_set_P.
       red; rewrite qe qe'; split => // a b gab.
       have: (inc a (substrate r)) by order_tac.
       by rewrite qe'; move=> /in_set0 ae.
    move => a b /Zo_P [pa _] /Zo_P [pb _].
    apply: ( fun_set_small_source pa pb).
  move: (cpred_pr pB pz) => [ppB sp].
  have ->: (p -c card_one = cpred p) by rewrite cpred_pr4 //; fprops.
  have ltp: (cpred p) <c p by rewrite {2} sp; fprops.
  rewrite binom_bad //.
  set qq:=Zo _ _ ; case: (emptyset_dichot qq).
    by move=> ->; apply: cardinal_set0.
  move=> [t tq]; move: tq => /Zo_P [] /fun_set_P [ft st tt] _.
  case: (emptyset_dichot (substrate r)) => h.
    by case: pz; rewrite /p h cardinal_set0.
  move: h=> [x xsr]; rewrite - st in xsr; move: (Vf_target ft xsr).
  by rewrite tt=> /in_set0.
move: (cpred_pr nB nz) => [pnB sn].
set q := (cpred n) in sn pnB.
have ->: ( (n +c p) -c \1c = q +c p).
  rewrite sn; apply: (cdiff_pr2 (BS_sum pnB pB) BS1).
  rewrite (csum_via_succ1 _ pnB) Bsucc_rw; fprops.
move: (finite_ordered_interval1 tor fsr) => [f [isf _]].
move: (finite_ordered_interval1 tor' fsr') => [g [isg _]].
move: (inverse_order_is isf)=> isif.
move: (inverse_order_is isg)=> isig.
rewrite- (cardinal_set_of_increasing_functions3 pnB pB).
rewrite -/n in isg; rewrite -/p in isf isif.
have ->: Bint_cco \0c q = Bint_co n.
  by rewrite /Bint_co/Bint_cco sn - Bint_co_cc /Bintcc.
set Q1:= functions_incr _ _.
set Q2:= functions_incr _ _.
set f' := inverse_fun f.
set g' := inverse_fun g.
set ff:= Lf (fun z => ((g \co z)) \co f') Q1 Q2.
have b_g: (bijection g) by move : isg=> [_ _ [ok _ _] _].
have i_g: (injection g) by exact (proj1 b_g).
have fg:function g by fct_tac.
have fif:function f' by move: isif => [_ _ [bg _ _] _]; fct_tac.
move: (order_isomorphism_increasing isg) => sig.
move: (order_isomorphism_increasing isif) => siif.
have tg: (substrate (Bint_co n) = target g).
  by move: sig => [_ _ [_ _ tg] _].
have soif : (substrate (Bint_co p) = source f')
  by move: siif => [_ _ [_ sf _] _].
have tf': (substrate r = target f') by move: siif => [_ _ [_ _ xx] _].
have sg : (substrate r' = source g) by move: sig => [_ _ [_ xx _]_].
have ta1:lf_axiom (fun z => (g \co z) \co f') Q1 Q2.
  move=> z /Zo_P [zs iz].
  move: (increasing_compose3 siif iz sig) => [p1 p2 p3].
  apply: Zo_i => //; rewrite tg soif //.
have ffc3: (forall w, inc w Q1 -> Vf (compose3function f' g) w
    = (g \co w) \co f').
  move => w wQ; move: (wQ) => /Zo_P [] /fun_set_P [fw sw tw] siw.
  rewrite c3f_V //; ue.
have s_f: (surjection f') by move : isif=> [_ _ [[_ ok] _ _]].
have s3: sub Q1 (source (compose3function f' g)).
  rewrite /compose3function /Q1 /functions_incr -tf' - sg.
  aw; apply: Zo_S.
apply /card_eqP.
exists ff; rewrite /ff; red;aw;split => //; apply: lf_bijective => //.
  move=> u v u1 v1;rewrite -(ffc3 _ u1) -(ffc3 _ v1).
  by move: (c3f_fi s_f i_g) => [_ h]; apply: h;apply: s3.
move=> y yQ2.
move: (isig) => [_ _ [qa qb qc] _].
have fg': function g' by fct_tac.
have b_f: (bijection f) by move : isf=> [_ _ [bg _ _]_].
have fif':function f by fct_tac.
move: (order_isomorphism_increasing isig) => sig'.
move: (order_isomorphism_increasing isf) => siif'.
move: (siif') => [_ _ [qa' qb' qc'] _].
have soig' :(substrate (Bint_co n) = source g') by rewrite qb.
set x := compose (compose g' y) f.
have xQ1: inc x Q1.
  move: yQ2=> /Zo_P [zs iz].
  move: (increasing_compose3 siif' iz sig'); simpl; move=> [p1 p2 p3].
  by apply: Zo_i => //; rewrite - qc -qb'.
ex_tac.
move: yQ2 => /Zo_P [] /fun_set_P [fy sy ty] _.
have c1: g' \coP y by split => //; ue.
have sysf: source y = target f by ue.
have c2: y \coP f by split => //; ue.
have fyg: function (y \co f) by fct_tac.
have tyg: target g = target (y \co f) by aw; ue.
have c4: g' \coP (y \co f) by split => //; aw; ue.
rewrite /x - (compfA c1 c2).
rewrite (compfA (composable_f_inv b_g) c4).
rewrite (bij_right_inverse b_g) tyg (compf_id_l fyg).
rewrite /f' -(compfA c2 (composable_f_inv b_f)) (bij_right_inverse b_f).
by rewrite - sysf (compf_id_r fy).
Qed.

Lemma binom_2plus n: inc n Bnat ->
  binom (succ n) \2c = (n *c (succ n)) %/c \2c.
Proof. move=> nB;rewrite binom2//. Qed.

Lemma binom_2plus0 n: inc n Bnat ->
  binom (succ n) \2c = (binom n \2c) +c n.
Proof.
move=> nB.
have oB: inc card_one Bnat by fprops.
by rewrite - succ_one (binomSnSm nB oB) (binom1 nB).
Qed.

Lemma cardinal_pairs_lt n: inc n Bnat ->
  cardinal (Zo (coarse Bnat)
    (fun z => [/\ \1c <=c (P z), (P z) <c (Q z) & (Q z) <=c n])) =
  (binom n \2c).
Proof.
move=> nB; rewrite /coarse.
set (E:= Bint1c n).
set T:=Zo _ _.
move: BS1 BS2 => oB tB.
case: (p_or_not_p (card_two <=c n)); last first.
  case: (card_le_to_el CS2 (CS_Bnat nB)).
    by move=> h h'; contradiction.
  move=> h _; rewrite binom_bad //; try apply: inc2_Bnat.
  case: (emptyset_dichot T); first by move=> ->; rewrite cardinal_set0.
  move=> [p pT]; move: pT => /Zo_P [a1 [a2 a3 a4]].
  have : (Q p) <c card_two by co_tac.
  rewrite - succ_one; move /(card_lt_succ_leP BS1) => a5.
  have a6: (P p) <c card_one by co_tac.
  co_tac.
move=> le2n.
have cE: cardinal E = n by rewrite card_Bint1c.
rewrite (subsets_with_p_elements_pr nB tB cE).
apply card_eqP.
exists (Lf (fun z=> (doubleton (P z) (Q z))) T
    (subsets_with_p_elements card_two E)).
split => //; aw; apply: lf_bijective.
    move=> z /Zo_P [zp [le1p [lepq npq] leqn]].
     have pE: inc (P z) E by apply /Bint_ccP1 => //; split => //;co_tac.
     have qE: inc (Q z) E by apply /Bint_ccP1 => //;split => //; co_tac.
    apply: Zo_i; last by apply: cardinal_set2.
    by apply /setP_P; apply: sub_set2.
 move=> u v /Zo_P [] /setX_P [pu _ _] [_ lt1 _]
     /Zo_P [] /setX_P [pv _ _] [_ lt2 _] h.
  case: (doubleton_inj h); move=> [e1 e2].
    apply: pair_exten =>//.
    move: lt1;rewrite e1 e2; move => [lt1 _]; co_tac.
move => y /Zo_P [] /setP_P yE cy2.
have yB: sub y Bnat.
  apply: (@sub_trans E) => //; apply: Bint_S.
have [a [b [p1 p2]]]: exists a, exists b, a <c b /\ doubleton a b = y.
  move: (set_of_card_two cy2)=> [a [b [ab yab]]].
  have aE: inc a Bnat by apply: yB; rewrite yab; fprops.
  have bE: inc b Bnat by apply: yB; rewrite yab; fprops.
  case: (card_le_to_el (CS_Bnat aE)(CS_Bnat bE)).
    move=> h; exists a; exists b; split => //; split=>//.
  by move=> h; exists b; exists a;split => //; rewrite set2_C.
exists (J a b); aw => //.
apply: Zo_i.
  have aE: inc a Bnat by apply: yB; rewrite -p2; fprops.
  have bE: inc b Bnat by apply: yB; rewrite -p2; fprops.
  aw; fprops.
have: inc a E by apply: yE; rewrite -p2; fprops.
have: inc b E by apply: yE; rewrite -p2; fprops.
by aw; move /(Bint_ccP1 BS1 nB) => [pa pb] /(Bint_ccP1 BS1 nB) [pc pd].
Qed.

Lemma cardinal_pairs_le n: inc n Bnat ->
  cardinal(Zo (coarse Bnat)
    (fun z=> [/\ \1c <=c (P z), (P z) <=c (Q z) & (Q z) <=c n])) =
     (binom (succ n) \2c).
Proof.
move=> nB.
rewrite (binom_2plus0 nB).
rewrite - cardinal_pairs_lt // /coarse.
set E1 := Zo _ _; set E2 := Zo _ _.
have s21: sub E2 E1.
  move=> t /Zo_P [pa [pb [pc _] pd]]; apply: Zo_i => //.
rewrite -(cardinal_setC s21).
suff: (E1 -c E2 = n) by move => ->.
set (T:= Bintcc card_one n).
have ->: n = cardinal T by rewrite card_Bint1c.
rewrite /card_diff; apply /card_eqP.
exists (Lf P (E1 -s E2) T); red;aw; split => //.
have cp: forall x, inc x (E1 -s E2) -> P x = Q x.
  move=> x /setC_P [] /Zo_P [xp [le1 le2 ne]] h.
  ex_middle npq; case: h; apply: Zo_i => //.
apply: lf_bijective.
    move=> x xc; move: (cp _ xc).
    move: xc => /setC_P [] /Zo_P [xp [le1 le2 le]] ns h.
    apply /(Bint_ccP1 BS1 nB); split => //; ue.
  move => u v uc vc; move: (cp _ vc) (cp _ uc) => h1 h2.
  move: uc vc => /setC_P [] /Zo_P [] /setX_P [pu _ _] _ _
       /setC_P [] /Zo_P [] /setX_P [pv _ _] _ _ sp.
   by apply: pair_exten => //; rewrite - h1 -h2 sp.
move=> y => /(Bint_ccP1 BS1 nB) [l1y lyn].
have yB: inc y Bnat by Bnat_tac.
exists (J y y); aw => //; apply /setC_P; split.
  apply: Zo_i; [ fprops | aw;split;fprops].
by move /Zo_hi => [_ bad _]; case: bad; aw.
Qed.

Lemma sum_of_i n: inc n Bnat ->
  card_sumb (Bint n) id = binom n \2c.
Proof.
move: n; apply: cardinal_c_induction.
  rewrite binom_bad; fprops.
  rewrite /card_sumb csum_trivial =>//; bw; apply: Bint_co00.
  apply: card_lt_02.
move=> n nB hr.
have aux: forall a, inc a Bnat -> cardinalp a by move=> a aB; fprops.
rewrite -induction_on_sum // hr binom_2plus0 //.
Qed.

Lemma fct_sum_const1 f n m:
  inc n Bnat -> (forall i, i <c n -> f i = m) ->
  card_sumb (Bint n) f = n *c m.
Proof.
move=> nB p; rewrite /card_sumb.
have <-: (cst_graph (Bint n) m = Lg (Bint n) f).
   rewrite /cst_graph; apply: Lg_exten.
   by move=> x => /(BintP nB) => h; symmetry; apply: p.
rewrite csum_of_same cprodC.
apply: cprod2_pr2=>//.
rewrite card_Bint //;symmetry;apply: card_card; fprops.
Qed.

Lemma sum_of_i3 n: inc n Bnat ->
  card_sumb (Bint n) id = binom n \2c.
Proof.
move=> nB; rewrite /card_sumb.
move: card_lt_02 => lt20.
case: (equal_or_not n \0c) => nz.
  rewrite nz csum_trivial ? binom_bad; fprops.
  bw; apply: Bint_co00.
move: (cpred_pr nB nz) => [pB nsp].
rewrite nsp binom2 //.
set p := cpred n in pB nsp |- *.
set sn:= card_sum _ .
set aux:= (p *c (succ p)).
suff: (sn +c sn = aux).
  move => h.
  have aB: inc aux Bnat by rewrite /aux; fprops.
  have iB: inc sn Bnat.
    have cn: cardinalp sn by rewrite /sn/card_sum; fprops.
    rewrite -h in aB; apply: (Bnat_in_sum cn aB).
  rewrite - two_times_n in h.
  apply: (cdivides_pr2 aB BS2 iB card2_nz (sym_equal h)).
move: (sum_of_sums (fun i => i) (fun i=> (p -c i))
     (Bint (succ p))).
rewrite nsp in nB.
have fim: (forall i : Set, i <c (succ p) ->
  (fun i : Set => i +c (p -ci)) i = p).
  move=> i /(card_lt_succ_leP pB) => ilp.
  apply: cdiff_pr =>//; Bnat_tac.
rewrite (fct_sum_const1 nB fim).
rewrite cprodC /aux; move => <-; apply: f_equal.
rewrite /sn - /(card_sumb _ _) fct_sum_rev //.
Qed.

Lemma sum_of_i2 n: inc n Bnat ->
  card_sumb (Bintcc \1c n) id =
  (binom (succ n) \2c).
Proof.
move => nB.
move: (sum_of_i3 (BS_succ nB)).
rewrite - (Bint_co_cc nB).
move: (Bint_pr5 nB) => [<- pb].
rewrite csumA_setU1 //; aw; rewrite /card_sumb /card_sum; fprops.
Qed.

Lemma sum_of_i2bis n: inc n Bnat ->
  card_sumb (Bintcc \1c n) id = (binom (succ n) \2c).
Proof.
move => nB.
rewrite - cardinal_pairs_le //.
set (E:= Bintcc card_one n).
move: BS1 => oB.
set X:=Zo _ _ .
set(f:= Lg E (fun k => Zo X (fun z => Q z = k))).
have p1: X = unionb f.
  rewrite /f; set_extens x.
    move => xX; move/Zo_P: (xX) => [xs [le1 le2 le3]]; apply /setUb_P; bw.
    have qE:inc (Q x) E by apply /(Bint_ccP1 BS1 nB); split => //; co_tac.
    by ex_tac; bw; apply: Zo_i.
  by move=> /setUb_P; bw; move => [y yE]; bw; move /Zo_P => [].
have p2: f= disjointU_fam (Lg E (fun i => Bintcc card_one i)).
  rewrite /f /disjointU_fam; bw; apply: Lg_exten.
  move=> x xE; move: (xE)=> /(Bint_ccP1 BS1 nB) [ox xn].
  have xB: inc x Bnat by Bnat_tac.
  bw; set_extens t.
    move => /Zo_P [] /Zo_P [] /setX_P [pt _ qB] [oP pq _] qt.
     apply /indexed_P;split => //; apply /(Bint_ccP1 BS1 xB); split => //; ue.
  move /indexed_P => [pt] /(Bint_ccP1 BS1 xB) [pa pb] pc.
  apply: Zo_i => //; apply /Zo_P; rewrite pc.
  split => //; apply /setX_P; rewrite pc.
  split => //; Bnat_tac.
have ->: X = disjointU (Lg E (fun i => Bintcc card_one i)).
  by rewrite p1 p2 /disjointU.
apply /card_eqP; apply: equipotent_disjointU1.
split;fprops; bw => i iE; bw.
move: iE => /(Bint_ccP1 BS1 nB) [_ lin].
have iB: inc i Bnat by Bnat_tac.
apply /card_eqP; rewrite card_Bint1c //.
apply: card_card; fprops.
Qed.

number of monomials

Lemma sof_sum_eq_equi F n: inc n Bnat ->
   (functions_sum_eq F n) \Eq (graphs_sum_eq F n).
Proof.
move=> nB.
exists (Lf graph (functions_sum_eq F n) (graphs_sum_eq F n)).
red;aw; split => //; apply: lf_bijective.
    move => t ts; apply /funI_P; ex_tac.
  move=> u v /Zo_S /fun_set_P [fu su tu] /Zo_S /fun_set_P [fv sv tv] ge.
  apply: function_exten3 =>//; try ue.
by move=> y /funI_P.
Qed.

Lemma sof_sum_le_equi F n: inc n Bnat ->
  (functions_sum_le F n) \Eq (graphs_sum_le F n).
Proof.
move=> nB.
exists (Lf graph (functions_sum_le F n) (graphs_sum_le F n)).
red;aw; split => //;apply: lf_bijective.
    move => t ts; apply /funI_P; ex_tac.
  move=> u v /Zo_S /fun_set_P [fu su tu] /Zo_S /fun_set_P
     [fv sv tv] ge.
  apply: function_exten3 =>//; try ue.
by move=> y /funI_P.
Qed.

Lemma set_of_functions_sum0 f:
  (forall a, inc a Bnat -> f \0c a = \1c) ->
  (forall a, inc a Bnat -> f a \0c = \1c) ->
  (forall a b, inc a Bnat -> inc b Bnat ->
     f (succ a) (succ b) = (f (succ a) b) +c (f a (succ b))) ->
  forall a b, inc a Bnat -> inc b Bnat -> f a b = (binom (a +c b) a).
Proof.
move=> p2 p3 p4.
move=> a b aB bB; move: a aB b bB.
apply: cardinal_c_induction.
  move=> b bB; rewrite p2; aw; [ rewrite binom0 =>// | fprops].
move=> n nB fnb b bB.
rewrite (csum_via_succ1 _ nB).
move: b bB; apply: cardinal_c_induction.
  have snB: inc (succ n) Bnat by fprops.
  by rewrite (bsum0r nB) (binom_nn snB) (p3 _ snB).
move=> c cB fsn.
have sc: inc (succ c) Bnat by fprops.
rewrite (p4 _ _ nB cB) (fnb _ sc) fsn.
by rewrite - (csum_via_succ _ cB) (binomSnSm (BS_sum nB sc) nB).
Qed.

Lemma CS_card_sum f: cardinalp (card_sum f).
Proof. rewrite /card_sum; fprops. Qed.

Lemma CS_card_prod f: cardinalp (card_prod f).
Proof. rewrite /card_prod; fprops. Qed.

Hint Resolve CS_card_sum CS_card_prod: fprops.

Lemma set_of_functions_sum1 E x n:
  inc n Bnat -> ~ (inc x E) ->
  (graphs_sum_le E n) \Eq (graphs_sum_eq (E +s1 x) n).
Proof.
move=> nB nxE.
set (K:= Bintc n).
set (f:= fun z=> z +s1 (J x (n -c (card_sum z)))).
exists (Lf f (graphs_sum_le E n)
    (graphs_sum_eq (E +s1 x) n)).
red;aw; split => //; apply: lf_bijective.
    move => z /(setof_suml_auxP _ nB) [dz lez fgz alc].
    apply /(setof_sume_auxP _ nB).
    have p0: (fgraph (f z)) by apply: fgraph_setU1 => //; ue.
    have p1: (E +s1 x) = domain (f z) by rewrite -dz domain_setU1 //.
    have xd: inc x (domain (f z)) by rewrite -p1; fprops.
    have Vx2: Vg (f z) x = (n -c (card_sum z)).
      rewrite /f setU1_V_out //; ue.
    have p2: cardinal_fam (f z).
      rewrite -dz in nxE; hnf.
      rewrite -p1; move=> i /setU1_P; case.
          rewrite -dz => idz; rewrite /f setU1_V_in //; apply: alc=>//.
      move => ->; rewrite Vx2 /card_diff; fprops.
    split => //.
    rewrite - (Lg_recovers p0) -p1 -/(card_sumb _ _) csumA_setU1 //.
    rewrite -dz /card_sumb.
    have ->: (Lg (domain z) (Vg(f z))) = z.
        apply /fgraph_exten => //;bw; fprops => t tf; rewrite /f; bw.
        rewrite setU1_V_in => //; ue.
    by rewrite Vx2; apply:cardinal_setC1.
  move => u v /(setof_suml_auxP _ nB) [fu su tu _].
  move /(setof_suml_auxP _ nB) => [fv sv tv _].
  apply: extension_injective => //; ue.
move=> y /(setof_sume_auxP _ nB) [fy sy ty suy].
  have pa: fgraph (Lg E (Vg y)) by fprops.
  have pb: cardinal_fam (Lg E (Vg y)).
    hnf; bw => t tE; bw; apply: suy; rewrite fy; fprops.
  have pc : n = card_sum (Lg E (Vg y)) +c Vg y x.
    rewrite - sy -{1} (Lg_recovers ty) -/(card_sumb (domain y) _).
    by rewrite fy (csumA_setU1 _ nxE).
   have pd: Vg y x = n -c card_sum (Lg E (Vg y)).
     rewrite pc in nB.
     rewrite pc csumC cdiff_pr1 //.
   apply: (Bnat_in_sum _ nB); apply: suy; rewrite fy; fprops.
   apply: (Bnat_in_sum2 _ nB); fprops.
exists (Lg E (Vg y)).
    apply /(setof_suml_auxP _ nB); bw;split => //; rewrite pc.
  apply:csum_M0le; fprops.
symmetry; rewrite /f;apply: fgraph_exten; fprops.
  apply fgraph_setU1; fprops; bw.
 by rewrite domain_setU1; bw.
rewrite domain_setU1; bw; move => t; case /setU1_P => te.
 rewrite setU1_V_in //; bw.
 rewrite te setU1_V_out //; bw.
Qed.

Lemma set_of_functions_sum2 E n: inc n Bnat ->
 cardinal(graphs_sum_le E (succ n))
 = (cardinal (graphs_sum_eq E (succ n)))
    +c (cardinal (graphs_sum_le E n)).
Proof.
move => nB.
have snB: inc (succ n) Bnat by fprops.
set A:= (graphs_sum_eq E (succ n)).
set B:= (graphs_sum_le E (succ n)).
set C:= (graphs_sum_le E n).
have di: disjoint A C.
  apply: disjoint_pr.
  move=> u; move /(setof_sume_auxP _ snB) => [_ pb _ _].
  move /(setof_suml_auxP _ nB) => [_].
  rewrite pb; move: (card_lt_succ nB) => qa qb; co_tac.
suff: B = A \cup C by move => ->; rewrite (csum2_pr5 di) csum2_pr2a csum2_pr2b.
set_extens t.
  move /(setof_suml_auxP _ snB) => [pa pb pc1 pc2]; apply /setU2_P.
  case: (equal_or_not (card_sum t) (succ n)) => h.
    left; apply /(setof_sume_auxP _ snB); split => //.
  right; apply /(setof_suml_auxP _ nB); split => //.
  by apply /(card_lt_succ_leP nB); split.
case /setU2_P.
   move /(setof_sume_auxP _ snB) => [pa pb pc1 pc2].
   apply /(setof_suml_auxP _ snB);split => //; rewrite pb; fprops.
move /(setof_suml_auxP _ nB) => [pa pb pc1 pc2].
apply /(setof_suml_auxP _ snB);split => //.
move: (card_le_succ nB)=> aux; co_tac.
Qed.

Lemma set_of_functions_sum3 E:
  cardinal (graphs_sum_le E \0c) = \1c.
Proof.
have zb: inc \0c Bnat by fprops.
set w:= graphs_sum_le _ _.
suff ->: (w = singleton (Lg E (fun _ =>\0c))) by apply: cardinal_set1.
apply: set1_pr.
  apply /(setof_suml_auxP _ zb); bw;split => //.
      rewrite csum_of_same cprodC cprod0r; fprops.
    fprops.
  hnf; bw => t ti; bw; fprops.
move => z zw.
move: (zw); rewrite /w/graphs_sum_le.
move /funI_P => [g] /Zo_S /fun_set_P [qa qb qc] qd.
move: zw => /(setof_suml_auxP _ zb) [pa pb pc pd].
apply: fgraph_exten; fprops; bw.
rewrite pa;move => i zi /=; bw.
rewrite -qb in zi.
move: (Vf_target qa zi); rewrite qc /Vf qd; move /(BintcP BS0).
apply: (card_le0).
Qed.

Lemma set_of_functions_sum4 n: inc n Bnat->
    cardinal (graphs_sum_le emptyset n) = \1c.
Proof.
move=> nB.
suff: (graphs_sum_le emptyset n =singleton emptyset).
  by move=> ->;apply: cardinal_set1.
apply: set1_pr.
  apply /(setof_suml_auxP _ nB);split; [bw | | fprops | ].
        rewrite csum_trivial; fprops; bw.
    apply: fgraph_set0.
  by move => t;rewrite domain_set0 => /in_set0.
move => z/ (setof_suml_auxP _ nB) [g df _ _].
by apply /domain_set0_P.
Qed.

Lemma set_of_functions_sum_pr n h:
  inc n Bnat -> inc h Bnat ->
  let intv:= fun h => (Bint h) in
    let sle:= fun n h => graphs_sum_le (intv h) n in
      let seq := fun n h => graphs_sum_eq (intv h) n in
        let A:= fun n h => cardinal (sle n h) in
          let B:= fun n h => cardinal (seq n h) in
            (A n h = B n (succ h) /\ A n h = (binom (n +c h) n)).
Proof.
move=> nB hB intv sle seq A B.
have AB: forall a b, inc a Bnat -> inc b Bnat -> A a b = B a (succ b).
  move=> a b aB bB; rewrite /A /B /sle/seq; apply /card_eqP.
  move: (Bint_pr4 bB) => [p1 p2].
  rewrite /intv -p1; apply: (set_of_functions_sum1 aB p2).
split; first by apply: AB.
have Hv: forall a b, inc a Bnat -> inc b Bnat ->
  A (succ a) b = (B (succ a) b) +c (A a b).
  move=> a b aB bB; rewrite /A/B /sle /seq.
  by rewrite - (set_of_functions_sum2 (intv b) aB).
apply: set_of_functions_sum0.
- move=> a aB; rewrite /A/sle; apply: set_of_functions_sum3.
- move=> a aB;rewrite /A/sle.
  have ->: (intv \0c = emptyset).
    by rewrite /intv;apply: Bint_co00.
  apply: set_of_functions_sum4 =>//.
- move=> a b aB bB.
  by rewrite (Hv _ _ aB (BS_succ bB)) -(AB _ _ (BS_succ aB) bB).
- exact.
- exact.
Qed.

Definition graphs_sum_le_int p n :=
  graphs_sum_le (Bintc p) n.

Definition functions_incr_int p n :=
  (Zo (functions (Bintc p) (Bintc n))
    (fun z => increasing_fun z
      (Bint_cco \0c p)
      (Bint_cco \0c n))).

Lemma card_set_of_increasing_functions_int p n:
  inc p Bnat -> inc n Bnat ->
  cardinal (functions_incr_int p n) =
  binom (succ (n +c p)) (succ p).
Proof.
move=> pB nB.
have spB: inc (succ p) Bnat by fprops.
rewrite -(csum_via_succ _ pB).
rewrite - (cardinal_set_of_increasing_functions3 nB spB).
rewrite /functions_incr_int /functions_incr.
have zB: inc \0c Bnat by fprops.
rewrite (proj2 (Bintco_wor _)) (proj2 (Binto_wor _ _)) - Bint_co_cc //.
have-> //: (Bint_co (succ p) = (Bint_cco \0c p)).
move: (Bint_co_cc pB).
rewrite /Bint_cco /Bintc /Bintcc => -> //.
Qed.

Lemma double_restrc f n p: fgraph f -> inc p Bnat ->
  n <c p ->
  domain f = Bintc p ->
  restr (restr f (Bintc (succ n)))
     (Bintc n) =
     restr f (Bintc n).
Proof.
move=> fgf pB ltnp df.
have nB: inc n Bnat by move: ltnp=> [h _]; Bnat_tac.
rewrite double_restr //; apply: Bintc_M; fprops.
Qed.

Lemma induction_on_sum3 f m:
  fgraph f -> inc m Bnat ->
  domain f = Bintc m ->
  (forall a, inc a (domain f) -> cardinalp (Vg f a)) ->
  (card_sum (restr f (Bintc \0c))= (Vg f \0c)
    /\ (forall n, n <=c m ->
      (card_sum (restr f (Bint n))) +c (Vg f n)
      = card_sum (restr f (Bint (succ n))))).
Proof.
move=> fgf mB df alc.
split.
  rewrite Bint_cc00.
  have zd: (inc \0c (domain f)) by rewrite df BintcP; fprops.
  rewrite csum_trivial4 card_card =>//; apply: alc =>//.
move=> n lenm.
have nB: inc n Bnat by Bnat_tac.
move: (Bint_pr4 nB) => [pa pb].
have qb: sub (Bint (succ n)) (domain f).
  by rewrite df - (Bint_co_cc nB); apply: Bintc_M.
have qa: sub (Bint n) (domain f).
  by apply: sub_trans qb; apply: Bint_M.
move: (csumA_setU1 (fun z => Vg f z) pb).
rewrite /card_sumb pa csumC //.
Qed.

Definition csum_to_increasing_fun y :=
  fun i => card_sum (restr y (Bintc i)).

Definition csum_to_increasing_fct y n p :=
  Lf (csum_to_increasing_fun y)
  (Bintc p) (Bintc n).

Lemma csum_to_increasing1 y n p:
  inc n Bnat -> inc p Bnat ->
  inc y (graphs_sum_le_int p n) ->
  lf_axiom (csum_to_increasing_fun y)
    (Bintc p)
    (Bintc n).
Proof.
move=> nB pB /(setof_suml_auxP _ nB) [dy dyxx les alc] u.
move /(BintcP pB) => up.
have sj:(sub (Bintc u) (domain y)).
  by rewrite dy; apply: Bintc_M.
move: (csum_increasing1 alc sj) => aux.
apply /(BintcP nB); co_tac.
Qed.

Lemma csum_to_increasing2 n p:
  inc n Bnat -> inc p Bnat ->
  lf_axiom (fun y=> (csum_to_increasing_fct y n p))
  (graphs_sum_le_int p n)
  (functions_incr_int p n).
Proof.
move=> nB pB y ys.
move: (csum_to_increasing1 nB pB ys) => ta1.
rewrite /csum_to_increasing_fct.
have aa: (forall u, inc u (domain y)-> inc (Vg y u) (Bintc n)).
  move: ys => /funI_P [z] /Zo_S /fun_set_P [fz sz tg] hz udy.
  rewrite hz -tg; aw; move=> h; apply: Vf_target =>//.
move: ys => /(setof_suml_auxP _ nB) [dy fhy les alc].
have ab: (forall u, inc u (domain y) -> inc (Vg y u) Bnat).
  move=> u udy; apply: (Bint_S (aa _ udy)).
set g:= Lf _ _ _ .
have p1: function g by apply: lf_function.
apply: Zo_i; first by apply /fun_set_P; split => //; rewrite /g;aw.
have zB: inc \0c Bnat by fprops.
move: (Binto_wor \0c p) => [[ok1 _ ] sr1].
move: (Binto_wor \0c n) => [[ok2 _ ] sr2].
split => //; rewrite /g;aw; first by split; aw; try ue.
move=> a b; move /Binto_gleP => [asg bsg leab]; apply /Binto_gleP; aw.
split.
  have ag: inc a (source g) by rewrite /g; aw.
  move: (Vf_target p1 ag); rewrite /g; aw.
  have bg: inc b (source g) by rewrite /g; aw.
  move: (Vf_target p1 bg); rewrite /g; aw.
rewrite /csum_to_increasing_fun.
set f:= restr y (Bintc b).
have fgf: fgraph f by rewrite /f; fprops.
move: (asg)(bsg) => /(BintcP pB) lap /(BintcP pB) lbp.
have si: sub (Bintc b) (domain y).
  by rewrite dy; apply: Bintc_M.
have df: domain f = (Bintc b) by rewrite /f; bw.
have fc:(forall x, inc x (domain f) -> cardinalp (Vg f x)).
   move=> x; rewrite df; move=> xdf; rewrite /f; bw; apply: alc.
   apply: si=>//.
set j := (Bintc a).
have bB: inc b Bnat by Bnat_tac.
have sj: sub j (domain f) by rewrite /f df;apply: Bintc_M.
have -> : restr y j = restr f j by rewrite /f double_restr // -df //.
exact (csum_increasing1 fc sj).
Qed.

Lemma csum_to_increasing4 n p:
  inc n Bnat -> inc p Bnat ->
  injection (Lf (fun y=> (csum_to_increasing_fct y n p))
  (graphs_sum_le_int p n)
  (functions_incr_int p n)).
Proof.
move=> nB pB; apply: lf_injective.
  apply: csum_to_increasing2 =>//.
rewrite /csum_to_increasing_fct.
move=> u v us vs h.
move: (csum_to_increasing1 nB pB vs)=> ta2.
have aux: forall x, inc x (Bintc p) ->
  card_sum (restr u (Bintc x)) =
   card_sum (restr v (Bintc x)).
  move=> x xi; move: (f_equal (Vf ^~ x) h); aw.
  apply: csum_to_increasing1 =>//.
clear h.
move: us vs; rewrite /graphs_sum_le_int.
move /(setof_suml_auxP _ nB)=> [du lesu fgu alcu].
move /(setof_suml_auxP _ nB)=> [dv lesv fgv alcv].
apply: fgraph_exten =>//; first by ue.
move: (induction_on_sum3 fgu pB du alcu) => [u1 u2].
move: (induction_on_sum3 fgv pB dv alcv) => [v1 v2].
move=> x xdu.
case: (equal_or_not x \0c)=> zx.
  rewrite zx -u1 -v1 aux =>//; apply /(BintcP pB); fprops.
have xlep: x <=c p by move: xdu; rewrite du; move /(BintcP pB).
have xB: inc x Bnat by rewrite du in xdu; apply: (Bint_S xdu).
move: (cpred_pr xB zx) => [prB xsp].
have i2:(Bint x = (Bintc (cpred x))).
  rewrite {1} xsp - Bint_co_cc //.
have xip: inc x (Bintc p) by ue.
have xpip: inc (cpred x) (Bintc p).
have psp: p <=c (succ p) by fprops.
   apply /(BintcP pB) /(card_le_succ_succP); fprops.
   rewrite -xsp; co_tac.
move: (u2 _ xlep)(v2 _ xlep); rewrite - Bint_co_cc // i2.
move: (ta2 _ xip); rewrite / csum_to_increasing_fun.
rewrite (aux _ xip) (aux _ xpip).
set A:= card_sum _; set B:= card_sum _.
move=> AB h1 h2; move: (Bint_S AB) => AB1.
apply: (@csum_simplifiable_left B) => //.
  have Bc: cardinalp B by rewrite /B /card_sum; fprops.
   rewrite -h1 in AB1;apply: (Bnat_in_sum2 Bc AB1).
  rewrite -h1 in AB1; apply: (Bnat_in_sum (alcu _ xdu) AB1).
  rewrite du -dv in xdu.
  rewrite -h2 in AB1; apply: (Bnat_in_sum (alcv _ xdu) AB1).
rewrite h1 h2//.
Qed.

Lemma csum_to_increasing5 n p:
  inc n Bnat -> inc p Bnat ->
  surjection (Lf (fun y=> (csum_to_increasing_fct y n p))
  (graphs_sum_le_int p n)
  (functions_incr_int p n)).
Proof.
move=> nB pB; apply: lf_surjective.
  apply: csum_to_increasing2 =>//.
move =>y /Zo_P [] /fun_set_P [fy sy ty] iy.
rewrite /graphs_sum_le_int /csum_to_increasing_fct.
set E1:= Bintc p in sy iy |- *.
set E2:= Bintc n in ty iy |- *.
have Hb:inc \0c E1 by apply /(BintcP pB); fprops.
set (a:= Vf y \0c).
have aE2: inc a E2 by rewrite -ty /a; Wtac.
have rec:(forall u, u<> \0c -> inc u (source y) ->
    exists v, [/\ inc v (source y), u = succ v, v = cpred u &
       (Vf y v) <=c (Vf y u)]).
  move=> u unz usy.
  have up: u <=c p by move: usy;rewrite sy; move/ (BintcP pB).
  have uB:inc u Bnat by Bnat_tac.
  move: (cpred_pr uB unz)=> [pn sp].
  have cp: cardinalp (cpred u) by fprops.
  move: (card_le_succ0 cp); rewrite - sp => lepu.
  have psy: (inc (cpred u) (source y)).
   rewrite sy; apply/ (BintcP pB); co_tac.
  have zB: inc \0c Bnat by fprops.
  exists (cpred u); split=> //; move: iy => [o1 o2 [_ s1 s2] op].
  have ge1: gle (Bint_cco \0c p) (cpred u) u.
    rewrite /E1 /Bintc in sy.
     apply/ (Binto_gleP); rewrite - sy;split => //.
  by move: (op _ _ ge1) => /(Binto_gleP) [_ []].
set (f:= fun i => Yo(i= \0c) a ((Vf y i) -c (Vf y (cpred i)))).
have f1p: (forall i, inc i E1 -> inc (f i) E2).
  move=> i i1; rewrite /f; Ytac h =>//.
  rewrite sy in rec; move: (rec _ h i1) => [v [vsy usv vp wle]].
  apply /(BintcP nB).
  rewrite - sy in i1 vsy.
  move : (Vf_target fy i1)(Vf_target fy vsy).
  rewrite ty ; move /(BintcP nB) => win /(BintcP nB) wvn.
  have wib: inc (Vf y i) Bnat by Bnat_tac.
  have wvb: inc (Vf y v) Bnat by Bnat_tac.
  move: (cdiff_le_symmetry wle) => h1; rewrite -vp; co_tac.
set (g:= Lg E1 f).
have fg: fgraph g by rewrite /g; fprops.
have dg: domain g = Bintc p by rewrite /g;bw.
have cg: forall a, inc a (domain g) -> cardinalp (Vg g a).
  rewrite /g; bw;move=> b bdg; rewrite /g; bw.
  move: (f1p _ bdg);rewrite /E2 => aux; move: (Bint_S aux) => wB.
  fprops.
move: (induction_on_sum3 fg pB dg cg)=> [g0 g1].
set (h:= fun i=> card_sum (restr g (Bintc i))).
have h0: (h \0c = Vf y \0c).
  rewrite /h g0 /g; bw; rewrite /f Y_true //.
have h1: forall i, inc i E1 -> h i = Vf y i.
  move=> i /(BintcP pB) => ip.
  apply: (cardinal_c_induction5 (r:=fun i=> h i = Vf y i) pB h0) =>//.
  move=> m mp; rewrite /h => hr.
  have mB: inc m Bnat by move: mp => [mp _]; Bnat_tac.
  have cm: cardinalp m by fprops.
  have smB: inc (succ m) Bnat by fprops.
  set (n1:= succ m).
  have n1p: (n1 <=c p) by apply /card_le_succ_ltP.
  move: (g1 _ n1p); rewrite /n1.
  rewrite - Bint_co_cc // - Bint_co_cc // hr; move=> <-.
  have snz: (succ m <> \0c) by apply: succ_nz.
  have sm1: inc (succ m) E1 by apply /(BintcP pB).
  rewrite /g; bw; rewrite /f Y_false // cpred_pr1 //.
  have smsy: (inc (succ m) (source y)) by ue.
  move: (rec _ snz smsy) => [v [vsy smsv vp wle]].
  have mv: m = v.
    apply: succ_injective1; fprops.
    move: vsy; rewrite sy; move /(BintcP pB) => [aux _]; fprops.
  rewrite -mv in wle.
  move: (Vf_target fy smsy); rewrite ty /E2 => wi.
  move: (Bint_S wi)=> wsB.
  apply: cdiff_pr =>//; Bnat_tac.
have p1: inc g (graphs_sum_le E1 n).
  apply /(setof_suml_auxP _ nB); split => //.
  have pe1: inc p E1 by apply /(BintcP pB); fprops.
  move: (h1 _ pe1); rewrite /h -dg restr_to_domain; fprops.
  move => ->.
  rewrite - sy in pe1; move: (Vf_target fy pe1).
  by rewrite ty; move/(BintcP nB).
ex_tac.
move :(csum_to_increasing1 nB pB p1) => aux.
apply: function_exten => //; aw.
  apply: lf_function => //.
rewrite sy; move=> x xsy /=; aw;rewrite -h1 //.
Qed.

Lemma csum_to_increasing6 n p:
  inc p Bnat -> inc n Bnat ->
  cardinal (graphs_sum_le_int p n) =
  binom (succ (n +c p)) (succ p).
Proof.
move=> pB nB.
rewrite - card_set_of_increasing_functions_int //.
apply /card_eqP.
exists (Lf (fun y=> (csum_to_increasing_fct y n p))
    (graphs_sum_le_int p n)
    (functions_incr_int p n)).
red;aw; split => //.
by split; [apply: csum_to_increasing4 | apply: csum_to_increasing5].
Qed.

End IntegerProps.
Export IntegerProps.