From mathcomp Require Import all_ssreflect.

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

partitions and related properties

The majority of the lemmas in this file is part of mathcomp PR 731

Section BigSetOps.

Variables T I : finType.
Implicit Types (U : {pred T}) (P : pred I) (A B : {set I}) (F : I -> {set T}).

Lemma bigcup0P P F :
  reflect (forall i, P i -> F i = set0) (\bigcup_(i | P i) F i == set0).
Proof.
rewrite -subset0; apply: (iffP bigcupsP) => sub0 i /sub0; last by move->.
by rewrite subset0 => /eqP.
Qed.

Lemma bigcup_disjointP U P F :
  reflect (forall i : I, P i -> [disjoint U & F i])
          [disjoint U & \bigcup_(i | P i) F i].
Proof.
apply: (iffP idP) => [disUF i Pp|]; last exact: bigcup_disjoint.
apply: disjointWr disUF; exact: bigcup_sup.
Qed.

End BigSetOps.

Lemma imset_cover (aT rT : finType) (P : {set {set aT}}) (f : aT -> rT) :
  [set f x | x in cover P] = \bigcup_(i in P) [set f x | x in i].
Proof.
apply/setP=> y; apply/imsetP/bigcupP => [|[A AP /imsetP[x xA ->]]].
  by move=> [x /bigcupP[A AP xA] ->]; exists A => //; rewrite imset_f.
by exists x => //; apply/bigcupP; exists A.
Qed.

Section partition.
Variable (T : finType) (P : {set {set T}}) (D : {set T}).
Implicit Types (A B S : {set T}).

Lemma partition0 : partition P D -> set0 \in P = false.
Proof. case/and3P => _ _. by apply: contraNF. Qed.

Lemma partition_neq0 B : partition P D -> B \in P -> B != set0.
Proof. by move=> partP; apply: contraTneq => ->; rewrite partition0. Qed.

Lemma partition_trivIset: partition P D -> trivIset P.
Proof. by case/and3P. Qed.

Lemma partitionS B : partition P D -> B \in P -> B \subset D.
Proof.
by move=> partP BP; rewrite -(cover_partition partP); apply: bigcup_max BP _.
Qed.

Lemma cover1 A : cover [set A] = A.
Proof. by rewrite /cover big_set1. Qed.

Lemma trivIset1 A : trivIset [set A].
Proof. by rewrite /trivIset cover1 big_set1. Qed.

Lemma trivIsetD Q : trivIset P -> trivIset (P :\: Q).
Proof.
move/trivIsetP => tP; apply/trivIsetP => A B /setDP[TA _] /setDP[TB _]; exact: tP.
Qed.

Lemma trivIsetU Q :
  trivIset Q -> trivIset P -> [disjoint cover Q & cover P] -> trivIset (Q :|: P).
Proof.
move => /trivIsetP tQ /trivIsetP tP dQP; apply/trivIsetP => A B.
move => /setUP[?|?] /setUP[?|?]; first [exact:tQ|exact:tP|move => _].
  by apply: disjointW dQP; rewrite bigcup_sup.
by rewrite disjoint_sym; apply: disjointW dQP; rewrite bigcup_sup.
Qed.

Lemma coverD1 S : trivIset P -> S \in P -> cover (P :\ S) = cover P :\: S.
Proof.
move/trivIsetP => tP SP; apply/setP => x; rewrite inE.
apply/bigcupP/idP => [[A /setD1P [ADS AP] xA]|/andP[xNS /bigcupP[A AP xA]]].
  by rewrite (disjointFr (tP _ _ _ _ ADS)) //=; apply/bigcupP; exists A.
by exists A; rewrite // !inE AP andbT; apply: contraNneq xNS => <-.
Qed.

Lemma partitionD1 S :
  partition P D -> S \in P -> partition (P :\ S) (D :\: S).
Proof.
case/and3P => /eqP covP trivP set0P SP.
by rewrite /partition inE (negbTE set0P) trivIsetD ?coverD1 -?covP ?eqxx ?andbF.
Qed.

Lemma partitionU1 S :
  partition P D -> S != set0 -> [disjoint S & D] -> partition (S |: P) (S :|: D).
Proof.
case/and3P => /eqP covP trivP set0P SD0 disSD.
rewrite /partition !inE (negbTE set0P) orbF [_ == S]eq_sym SD0 andbT.
rewrite /cover bigcup_setU big_set1 -covP eqxx /=.
by move: disSD; rewrite -covP=> /bigcup_disjointP/trivIsetU1 => -[].
Qed.

Lemma partition_set0 : partition P set0 = (P == set0).
Proof.
apply/and3P/eqP => [[/bigcup0P covP _ ]|->]; last first.
  by rewrite /partition inE /trivIset/cover !big_set0 cards0 !eqxx.
by apply: contraNeq => /set0Pn[B BP]; rewrite -(covP B BP).
Qed.

Section Image.
Variables (T' : finType) (f : T -> T') (inj_f : injective f).
Let fP := [set f @: (S : {set T}) | S in P].

Lemma imset_inj : injective (fun A : {set T} => f @: A).
Proof.
move => A B => /setP E; apply/setP => x.
by rewrite -(mem_imset_eq (mem A) x inj_f) E mem_imset_eq.
Qed.

Lemma imset_disjoint (A B : {pred T}) :
  [disjoint f @: A & f @: B] = [disjoint A & B].
Proof.
apply/pred0Pn/pred0Pn => /= [[? /andP[/imsetP[x xA ->]] xB]|].
  by exists x; rewrite xA -(mem_imset_eq (mem B) x inj_f).
by move => [x /andP[xA xB]]; exists (f x); rewrite !mem_imset_eq ?xA.
Qed.

Lemma imset_trivIset : trivIset P = trivIset fP.
Proof.
apply/trivIsetP/trivIsetP.
- move=> trivP ? ? /imsetP[A AP ->] /imsetP[B BP ->].
  by rewrite (inj_eq imset_inj) imset_disjoint; apply: trivP.
- move=> trivP A B AP BP; rewrite -imset_disjoint -(inj_eq imset_inj).
  by apply: trivP; rewrite imset_f.
Qed.

Lemma imset0mem : (set0 \in fP) = (set0 \in P).
Proof.
apply/imsetP/idP => [[A AP /esym/eqP]|P0]; last by exists set0; rewrite ?imset0.
by rewrite imset_eq0 => /eqP<-.
Qed.

Lemma imset_partition : partition P D = partition fP (f @: D).
Proof.
suff cov: (cover fP == f @:D) = (cover P == D).
  by rewrite /partition -imset_trivIset imset0mem cov.
by rewrite /fP cover_imset -imset_cover (inj_eq imset_inj).
Qed.
End Image.

Lemma partition_pigeonhole A :
  partition P D -> #|P| <= #|A| -> A \subset D -> {in P, forall B, #|A :&: B| <= 1} ->
  {in P, forall B, A :&: B != set0}.
Proof.
move=> partP card_A_P /subsetP subAD sub1; apply/forall_inP.
apply: contraTT card_A_P => /forall_inPn [B BP]; rewrite negbK => eq0.
rewrite -!ltnNge -(setD1K BP) cardsU1 !inE eqxx /= add1n ltnS.
have F (x : T) (xA : x \in A) : { C | (C \in P) & (x \in C) }.
  by apply/sig2W/bigcupP; rewrite -/(cover P) (cover_partition partP) subAD.
pose f (x : T) : {set T} :=
  if @idP (x \in A) is ReflectT xA then s2val (F _ xA) else set0.
have inj_f : {in A &, injective f}.
{ move => x y; rewrite /f;
  case : {1}_ / idP => // xA _; case : {1}_ / idP => // yA _ E.
  case: (F x xA) E (s2valP' (F y yA)) => /= C CP xC <- yC.
  by have/card_le1_eqP/(_ y x) := sub1 _ CP; apply; apply/setIP. }
rewrite -(card_in_imset inj_f); apply: subset_leq_card.
apply/subsetP => ? /imsetP[x xA ->]; rewrite /f; move: xA.
case : {1}_ / idP => // xA _; case: (F x xA) => /= C CP xC; rewrite !inE CP andbT.
by apply: contraTneq eq0 => <-; apply/set0Pn; exists x; apply/setIP.
Qed.

End partition.

Lemma indexed_partition (I T : finType) (J : {pred I}) (B : I -> {set T}) :
  let P := [set B i | i in J] in
  {in J &, forall i j : I, j != i -> [disjoint B i & B j]} ->
  (forall i : I, J i -> B i != set0) -> partition P (cover P) /\ {in J&, injective B}.
Proof.
move=> P disjB inhB.
have s0NP : set0 \notin P.
  by apply/negP => /imsetP[x xI /eqP]; apply/negP; rewrite eq_sym inhB.
by rewrite /partition eqxx s0NP andbT /=; apply: trivIimset.
Qed.

(* TOTHINK: an alternative definition would be [set B :&: A | B in P]:\ set0
   Then one has to prove the partition properties, but the lemmas below 
   are simpler to prove. *)


(* This is not part of PR 731 *)

Section partition.
Variable (T : finType) (P : {set {set T}}) (D : {set T}).
Implicit Types (A B S : {set T}).

Definition sub_partition A : {set {set T}} :=
  preim_partition (pblock P) A.

Lemma sub_partitionP A : partition (sub_partition A) A.
Proof. exact: preim_partitionP. Qed.

Lemma sub_partition_sub A :
  partition P D -> A \subset D -> sub_partition A \subset [set B :&: A | B in P].
Proof.
move=> partP /subsetP subAD; apply/subsetP => B; case/imsetP => [x xA ->].
have ? : x \in cover P by rewrite (cover_partition partP) subAD.
apply/imsetP; exists (pblock P x); first by rewrite pblock_mem.
by apply/setP => y; rewrite !inE eq_pblock 1?andbC //; case/and3P: partP.
Qed.

Lemma card_sub_partition A :
  partition P D -> A \subset D -> #|sub_partition A| <= #|P|.
Proof.
move=> partP subAD; apply: leq_trans (leq_imset_card (fun B => B :&: A) _).
apply: subset_leq_card. exact: sub_partition_sub.
Qed.

End partition.