Section pigeon_list.
Variable (X : Type).
Implicit Types (l m : list X).
Inductive list_has_dup : list X -> Prop :=
| in_list_hd0 : forall l x, In x l -> list_has_dup (x::l)
| in_list_hd1 : forall l x, list_has_dup l -> list_has_dup (x::l).
Fact list_hd_cons_inv x l : list_has_dup (x::l) -> In x l \/ list_has_dup l.
Fact perm_list_has_dup l m : l ~p m -> list_has_dup l -> list_has_dup m.
Fact list_has_dup_app_inv l m : list_has_dup (l++m) -> list_has_dup l
\/ list_has_dup m
\/ exists x, In x l /\ In x m.
Fact list_has_dup_eq_duplicates m: list_has_dup m <-> exists x aa bb cc, m = aa++x::bb++x::cc.
Definition list_has_dup_equiv := list_has_dup_eq_duplicates.
Fact repeat_choice_two x m : Forall (eq x) m -> (exists m', m = x::x::m') \/ m = nil \/ m = x::nil.
(* If m in included in x::l then a) either m is included in l b) or m has a duplicate (x but that does not matter here) c) or m is permutable with x::m' with m' included in l *)
Fact incl_right_cons_incl_or_lhd_or_perm m x l :
incl m (x::l) -> incl m l
\/ list_has_dup m
\/ exists m', m ~p x::m' /\ incl m' l.
Fact incl_left_right_php x l y m : incl (y::m) (x::l) -> list_has_dup (y::m)
\/ x = y  /\ incl m l
\/ In y l /\ incl m l
\/ In y l /\ exists m', m ~p x::m' /\ incl m' l.
(* length_le_and_incl_implies_dup_or_perm is a generalisation of the PHP for which the inductive case works w/o needing decidable equality  A shorter proof  The proof is by induction on l *)
(* ** Generalized statement *)
(* If  m is strictly longer than l and m is (set) included in l then it has a duplicate  This proof does not require weakly decidable equality and it does not find where is the duplicate *)
(* ** The Finite PHP on lists of the same type *)

Theorem partition_intersection l m k :
length k < length (l++m)
-> incl (l++m) k
-> list_has_dup l
\/ list_has_dup m
\/ exists x, In x l /\ In x m.