/-
Copyright (c) 2020 Kyle Miller. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kyle Miller, Yury Kudryashov

! This file was ported from Lean 3 source module combinatorics.pigeonhole
! leanprover-community/mathlib commit 63f84d91dd847f50bae04a01071f3a5491934e36
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Nat.Modeq
import Mathbin.Data.Set.Finite
import Mathbin.Algebra.BigOperators.Order
import Mathbin.Algebra.Module.Basic
import Mathbin.Algebra.Module.BigOperators

/-!
# Pigeonhole principles

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

Given pigeons (possibly infinitely many) in pigeonholes, the
pigeonhole principle states that, if there are more pigeons than
pigeonholes, then there is a pigeonhole with two or more pigeons.

There are a few variations on this statement, and the conclusion can
be made stronger depending on how many pigeons you know you might
have.

The basic statements of the pigeonhole principle appear in the
following locations:

* `data.finset.basic` has `finset.exists_ne_map_eq_of_card_lt_of_maps_to`
* `data.fintype.basic` has `fintype.exists_ne_map_eq_of_card_lt`
* `data.fintype.basic` has `finite.exists_ne_map_eq_of_infinite`
* `data.fintype.basic` has `finite.exists_infinite_fiber`
* `data.set.finite` has `set.infinite.exists_ne_map_eq_of_maps_to`

This module gives access to these pigeonhole principles along with 20 more.
The versions vary by:

* using a function between `fintype`s or a function between possibly infinite types restricted to
  `finset`s;
* counting pigeons by a general weight function (`∑ x in s, w x`) or by heads (`finset.card s`);
* using strict or non-strict inequalities;
* establishing upper or lower estimate on the number (or the total weight) of the pigeons in one
  pigeonhole;
* in case when we count pigeons by some weight function `w` and consider a function `f` between
  `finset`s `s` and `t`, we can either assume that each pigeon is in one of the pigeonholes
  (`∀ x ∈ s, f x ∈ t`), or assume that for `y ∉ t`, the total weight of the pigeons in this
  pigeonhole `∑ x in s.filter (λ x, f x = y), w x` is nonpositive or nonnegative depending on
  the inequality we are proving.

Lemma names follow `mathlib` convention (e.g.,
`finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum`); "pigeonhole principle" is mentioned in the
docstrings instead of the names.

## See also

* `ordinal.infinite_pigeonhole`: pigeonhole principle for cardinals, formulated using cofinality;

* `measure_theory.exists_nonempty_inter_of_measure_univ_lt_tsum_measure`,
  `measure_theory.exists_nonempty_inter_of_measure_univ_lt_sum_measure`: pigeonhole principle in a
  measure space.

## Tags

pigeonhole principle
-/

universe u v w

variable {α : Type u} {β : Type v} {M : Type w} [DecidableEq β]

open Nat

open BigOperators

namespace Finset

variable {s : Finset α} {t : Finset β} {f : α → β} {w : α → M} {b : M} {n : ℕ}

/-!
### The pigeonhole principles on `finset`s, pigeons counted by weight

In this section we prove the following version of the pigeonhole principle: if the total weight of a
finite set of pigeons is greater than `n • b`, and they are sorted into `n` pigeonholes, then for
some pigeonhole, the total weight of the pigeons in this pigeonhole is greater than `b`, and a few
variations of this theorem.

The principle is formalized in the following way, see
`finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum`: if `f : α → β` is a function which maps all
elements of `s : finset α` to `t : finset β` and `card t • b < ∑ x in s, w x`, where `w : α → M` is
a weight function taking values in a `linear_ordered_cancel_add_comm_monoid`, then for
some `y ∈ t`, the sum of the weights of all `x ∈ s` such that `f x = y` is greater than `b`.

There are a few bits we can change in this theorem:

* reverse all inequalities, with obvious adjustments to the name;
* replace the assumption `∀ a ∈ s, f a ∈ t` with
  `∀ y ∉ t, (∑ x in s.filter (λ x, f x = y), w x) ≤ 0`,
  and replace `of_maps_to` with `of_sum_fiber_nonpos` in the name;
* use non-strict inequalities assuming `t` is nonempty.

We can do all these variations independently, so we have eight versions of the theorem.
-/

section

variable [LinearOrderedCancelAddCommMonoid M]

/-!
#### Strict inequality versions
-/

/- warning: finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum -> Finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
Case conversion may be inaccurate. Consider using '#align finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum Finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sumₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version:
if the total weight of a finite set of pigeons is greater than `n • b`, and they are sorted into
`n` pigeonholes, then for some pigeonhole, the total weight of the pigeons in this pigeonhole is
greater than `b`. -/
theorem exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum (hf : ∀ a ∈ s, f a ∈ t)
    (hb : t.card • b < ∑ x in s, w x) : ∃ y ∈ t, b < ∑ x in s.filterₓ fun x => f x = y, w x :=
  exists_lt_of_sum_lt <| by simpa only [sum_fiberwise_of_maps_to hf, sum_const]
#align finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum Finset.exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum

/- warning: finset.exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul -> Finset.exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
Case conversion may be inaccurate. Consider using '#align finset.exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul Finset.exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmulₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version:
if the total weight of a finite set of pigeons is less than `n • b`, and they are sorted into `n`
pigeonholes, then for some pigeonhole, the total weight of the pigeons in this pigeonhole is less
than `b`. -/
theorem exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul (hf : ∀ a ∈ s, f a ∈ t)
    (hb : (∑ x in s, w x) < t.card • b) : ∃ y ∈ t, (∑ x in s.filterₓ fun x => f x = y, w x) < b :=
  @exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum α β Mᵒᵈ _ _ _ _ _ _ _ hf hb
#align finset.exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul Finset.exists_sum_fiber_lt_of_maps_to_of_sum_lt_nsmul

/- warning: finset.exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum -> Finset.exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) (OfNat.ofNat.{u3} M 0 (OfNat.mk.{u3} M 0 (Zero.zero.{u3} M (AddZeroClass.toHasZero.{u3} M (AddMonoid.toAddZeroClass.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))))))))) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) (OfNat.ofNat.{u3} M 0 (Zero.toOfNat0.{u3} M (AddRightCancelMonoid.toZero.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))))) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
Case conversion may be inaccurate. Consider using '#align finset.exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum Finset.exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sumₓ'. -/
/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (y «expr ∉ » t) -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version:
if the total weight of a finite set of pigeons is greater than `n • b`, they are sorted into some
pigeonholes, and for all but `n` pigeonholes the total weight of the pigeons there is nonpositive,
then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole
is greater than `b`. -/
theorem exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum
    (ht : ∀ (y) (_ : y ∉ t), (∑ x in s.filterₓ fun x => f x = y, w x) ≤ 0)
    (hb : t.card • b < ∑ x in s, w x) : ∃ y ∈ t, b < ∑ x in s.filterₓ fun x => f x = y, w x :=
  exists_lt_of_sum_lt <|
    calc
      (∑ y in t, b) < ∑ x in s, w x := by simpa
      _ ≤ ∑ y in t, ∑ x in s.filterₓ fun x => f x = y, w x :=
        sum_le_sum_fiberwise_of_sum_fiber_nonpos ht

#align finset.exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum Finset.exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum

/- warning: finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul -> Finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (OfNat.ofNat.{u3} M 0 (OfNat.mk.{u3} M 0 (Zero.zero.{u3} M (AddZeroClass.toHasZero.{u3} M (AddMonoid.toAddZeroClass.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))))))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (OfNat.ofNat.{u3} M 0 (Zero.toOfNat0.{u3} M (AddRightCancelMonoid.toZero.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
Case conversion may be inaccurate. Consider using '#align finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul Finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmulₓ'. -/
/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (y «expr ∉ » t) -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, strict inequality version:
if the total weight of a finite set of pigeons is less than `n • b`, they are sorted into some
pigeonholes, and for all but `n` pigeonholes the total weight of the pigeons there is nonnegative,
then for at least one of these `n` pigeonholes, the total weight of the pigeons in this pigeonhole
is less than `b`. -/
theorem exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul
    (ht : ∀ (y) (_ : y ∉ t), (0 : M) ≤ ∑ x in s.filterₓ fun x => f x = y, w x)
    (hb : (∑ x in s, w x) < t.card • b) : ∃ y ∈ t, (∑ x in s.filterₓ fun x => f x = y, w x) < b :=
  @exists_lt_sum_fiber_of_sum_fiber_nonpos_of_nsmul_lt_sum α β Mᵒᵈ _ _ _ _ _ _ _ ht hb
#align finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul Finset.exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul

/-!
#### Non-strict inequality versions
-/

/- warning: finset.exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum -> Finset.exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
Case conversion may be inaccurate. Consider using '#align finset.exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum Finset.exists_le_sum_fiber_of_maps_to_of_nsmul_le_sumₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality
version: if the total weight of a finite set of pigeons is greater than or equal to `n • b`, and
they are sorted into `n > 0` pigeonholes, then for some pigeonhole, the total weight of the pigeons
in this pigeonhole is greater than or equal to `b`. -/
theorem exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty)
    (hb : t.card • b ≤ ∑ x in s, w x) : ∃ y ∈ t, b ≤ ∑ x in s.filterₓ fun x => f x = y, w x :=
  exists_le_of_sum_le ht <| by simpa only [sum_fiberwise_of_maps_to hf, sum_const]
#align finset.exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum Finset.exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum

/- warning: finset.exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul -> Finset.exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
Case conversion may be inaccurate. Consider using '#align finset.exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul Finset.exists_sum_fiber_le_of_maps_to_of_sum_le_nsmulₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality
version: if the total weight of a finite set of pigeons is less than or equal to `n • b`, and they
are sorted into `n > 0` pigeonholes, then for some pigeonhole, the total weight of the pigeons in
this pigeonhole is less than or equal to `b`. -/
theorem exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty)
    (hb : (∑ x in s, w x) ≤ t.card • b) : ∃ y ∈ t, (∑ x in s.filterₓ fun x => f x = y, w x) ≤ b :=
  @exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum α β Mᵒᵈ _ _ _ _ _ _ _ hf ht hb
#align finset.exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul Finset.exists_sum_fiber_le_of_maps_to_of_sum_le_nsmul

/- warning: finset.exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum -> Finset.exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) (OfNat.ofNat.{u3} M 0 (OfNat.mk.{u3} M 0 (Zero.zero.{u3} M (AddZeroClass.toHasZero.{u3} M (AddMonoid.toAddZeroClass.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))))))))) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) (OfNat.ofNat.{u3} M 0 (Zero.toOfNat0.{u3} M (AddRightCancelMonoid.toZero.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))))) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x))) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) b (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))))
Case conversion may be inaccurate. Consider using '#align finset.exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum Finset.exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sumₓ'. -/
/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (y «expr ∉ » t) -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality
version: if the total weight of a finite set of pigeons is greater than or equal to `n • b`, they
are sorted into some pigeonholes, and for all but `n > 0` pigeonholes the total weight of the
pigeons there is nonpositive, then for at least one of these `n` pigeonholes, the total weight of
the pigeons in this pigeonhole is greater than or equal to `b`. -/
theorem exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum
    (hf : ∀ (y) (_ : y ∉ t), (∑ x in s.filterₓ fun x => f x = y, w x) ≤ 0) (ht : t.Nonempty)
    (hb : t.card • b ≤ ∑ x in s, w x) : ∃ y ∈ t, b ≤ ∑ x in s.filterₓ fun x => f x = y, w x :=
  exists_le_of_sum_le ht <|
    calc
      (∑ y in t, b) ≤ ∑ x in s, w x := by simpa
      _ ≤ ∑ y in t, ∑ x in s.filterₓ fun x => f x = y, w x :=
        sum_le_sum_fiberwise_of_sum_fiber_nonpos hf

#align finset.exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum Finset.exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum

/- warning: finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul -> Finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (OfNat.ofNat.{u3} M 0 (OfNat.mk.{u3} M 0 (Zero.zero.{u3} M (AddZeroClass.toHasZero.{u3} M (AddMonoid.toAddZeroClass.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))))))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {w : α -> M} {b : M} [_inst_2 : LinearOrderedCancelAddCommMonoid.{u3} M], (forall (y : β), (Not (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t)) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (OfNat.ofNat.{u3} M 0 (Zero.toOfNat0.{u3} M (AddRightCancelMonoid.toZero.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)))) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) s (fun (x : α) => w x)) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddRightCancelMonoid.toAddMonoid.{u3} M (AddCancelMonoid.toAddRightCancelMonoid.{u3} M (AddCancelCommMonoid.toAddCancelMonoid.{u3} M (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)))) (Finset.sum.{u3, u1} M α (OrderedCancelAddCommMonoid.toAddCommMonoid.{u3} M (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u3} M _inst_2)) (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s) (fun (x : α) => w x)) b)))
Case conversion may be inaccurate. Consider using '#align finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul Finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmulₓ'. -/
/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (y «expr ∉ » t) -/
/-- The pigeonhole principle for finitely many pigeons counted by weight, non-strict inequality
version: if the total weight of a finite set of pigeons is less than or equal to `n • b`, they are
sorted into some pigeonholes, and for all but `n > 0` pigeonholes the total weight of the pigeons
there is nonnegative, then for at least one of these `n` pigeonholes, the total weight of the
pigeons in this pigeonhole is less than or equal to `b`. -/
theorem exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul
    (hf : ∀ (y) (_ : y ∉ t), (0 : M) ≤ ∑ x in s.filterₓ fun x => f x = y, w x) (ht : t.Nonempty)
    (hb : (∑ x in s, w x) ≤ t.card • b) : ∃ y ∈ t, (∑ x in s.filterₓ fun x => f x = y, w x) ≤ b :=
  @exists_le_sum_fiber_of_sum_fiber_nonpos_of_nsmul_le_sum α β Mᵒᵈ _ _ _ _ _ _ _ hf ht hb
#align finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul Finset.exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul

end

variable [LinearOrderedCommSemiring M]

/-!
### The pigeonhole principles on `finset`s, pigeons counted by heads

In this section we formalize a few versions of the following pigeonhole principle: there is a
pigeonhole with at least as many pigeons as the ceiling of the average number of pigeons across all
pigeonholes.

First, we can use strict or non-strict inequalities. While the versions with non-strict inequalities
are weaker than those with strict inequalities, sometimes it might be more convenient to apply the
weaker version. Second, we can either state that there exists a pigeonhole with at least `n`
pigeons, or state that there exists a pigeonhole with at most `n` pigeons. In the latter case we do
not need the assumption `∀ a ∈ s, f a ∈ t`.

So, we prove four theorems: `finset.exists_lt_card_fiber_of_maps_to_of_mul_lt_card`,
`finset.exists_le_card_fiber_of_maps_to_of_mul_le_card`,
`finset.exists_card_fiber_lt_of_card_lt_mul`, and `finset.exists_card_fiber_le_of_card_le_mul`. -/

/- warning: finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to -> Finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))) (Finset.card.{u2} β t) b) ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α s))) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) b ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))))))) (Finset.card.{u2} β t) b) (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α s))) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) b (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))))))
Case conversion may be inaccurate. Consider using '#align finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to Finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_toₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with
at least as many pigeons as the ceiling of the average number of pigeons across all pigeonholes. -/
theorem exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t)
    (ht : t.card • b < s.card) : ∃ y ∈ t, b < (s.filterₓ fun x => f x = y).card :=
  by
  simp_rw [cast_card] at ht⊢
  exact exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum hf ht
#align finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to Finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to

/- warning: finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to -> Finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (LT.lt.{0} Nat Nat.hasLt (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (Finset.card.{u2} β t) n) (Finset.card.{u1} α s)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{0} Nat Nat.hasLt n (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (LT.lt.{0} Nat instLTNat (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat instMulNat) (Finset.card.{u2} β t) n) (Finset.card.{u1} α s)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{0} Nat instLTNat n (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)))))
Case conversion may be inaccurate. Consider using '#align finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to Finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_toₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with
at least as many pigeons as the ceiling of the average number of pigeons across all pigeonholes.
("The maximum is at least the mean" specialized to integers.)

More formally, given a function between finite sets `s` and `t` and a natural number `n` such that
`card t * n < card s`, there exists `y ∈ t` such that its preimage in `s` has more than `n`
elements. -/
theorem exists_lt_card_fiber_of_mul_lt_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t)
    (hn : t.card * n < s.card) : ∃ y ∈ t, n < (s.filterₓ fun x => f x = y).card :=
  exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to hf hn
#align finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to Finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to

/- warning: finset.exists_card_fiber_lt_of_card_lt_nsmul -> Finset.exists_card_fiber_lt_of_card_lt_nsmul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α s)) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))) b)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α s)) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{u3} M (Preorder.toLT.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))) b)))
Case conversion may be inaccurate. Consider using '#align finset.exists_card_fiber_lt_of_card_lt_nsmul Finset.exists_card_fiber_lt_of_card_lt_nsmulₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with
at most as many pigeons as the floor of the average number of pigeons across all pigeonholes. -/
theorem exists_card_fiber_lt_of_card_lt_nsmul (ht : ↑s.card < t.card • b) :
    ∃ y ∈ t, ↑(s.filterₓ fun x => f x = y).card < b :=
  by
  simp_rw [cast_card] at ht⊢
  exact
    exists_sum_fiber_lt_of_sum_fiber_nonneg_of_sum_lt_nsmul
      (fun _ _ => sum_nonneg fun _ _ => zero_le_one) ht
#align finset.exists_card_fiber_lt_of_card_lt_nsmul Finset.exists_card_fiber_lt_of_card_lt_nsmul

/- warning: finset.exists_card_fiber_lt_of_card_lt_mul -> Finset.exists_card_fiber_lt_of_card_lt_mul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (LT.lt.{0} Nat Nat.hasLt (Finset.card.{u1} α s) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (Finset.card.{u2} β t) n)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LT.lt.{0} Nat Nat.hasLt (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)) n)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (LT.lt.{0} Nat instLTNat (Finset.card.{u1} α s) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat instMulNat) (Finset.card.{u2} β t) n)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LT.lt.{0} Nat instLTNat (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)) n)))
Case conversion may be inaccurate. Consider using '#align finset.exists_card_fiber_lt_of_card_lt_mul Finset.exists_card_fiber_lt_of_card_lt_mulₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: there is a pigeonhole with
at most as many pigeons as the floor of the average number of pigeons across all pigeonholes.  ("The
minimum is at most the mean" specialized to integers.)

More formally, given a function `f`, a finite sets `s` in its domain, a finite set `t` in its
codomain, and a natural number `n` such that `card s < card t * n`, there exists `y ∈ t` such that
its preimage in `s` has less than `n` elements. -/
theorem exists_card_fiber_lt_of_card_lt_mul (hn : s.card < t.card * n) :
    ∃ y ∈ t, (s.filterₓ fun x => f x = y).card < n :=
  exists_card_fiber_lt_of_card_lt_nsmul hn
#align finset.exists_card_fiber_lt_of_card_lt_mul Finset.exists_card_fiber_lt_of_card_lt_mul

/- warning: finset.exists_le_card_fiber_of_nsmul_le_card_of_maps_to -> Finset.exists_le_card_fiber_of_nsmul_le_card_of_maps_to is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))) (Finset.card.{u2} β t) b) ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α s))) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) b ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))))))) (Finset.card.{u2} β t) b) (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α s))) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) b (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))))))
Case conversion may be inaccurate. Consider using '#align finset.exists_le_card_fiber_of_nsmul_le_card_of_maps_to Finset.exists_le_card_fiber_of_nsmul_le_card_of_maps_toₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: given a function between
finite sets `s` and `t` and a number `b` such that `card t • b ≤ card s`, there exists `y ∈ t` such
that its preimage in `s` has at least `b` elements.
See also `finset.exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to` for a stronger statement. -/
theorem exists_le_card_fiber_of_nsmul_le_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty)
    (hb : t.card • b ≤ s.card) : ∃ y ∈ t, b ≤ (s.filterₓ fun x => f x = y).card :=
  by
  simp_rw [cast_card] at hb⊢
  exact exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum hf ht hb
#align finset.exists_le_card_fiber_of_nsmul_le_card_of_maps_to Finset.exists_le_card_fiber_of_nsmul_le_card_of_maps_to

/- warning: finset.exists_le_card_fiber_of_mul_le_card_of_maps_to -> Finset.exists_le_card_fiber_of_mul_le_card_of_maps_to is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (forall (a : α), (Membership.Mem.{u1, u1} α (Finset.{u1} α) (Finset.hasMem.{u1} α) a s) -> (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{0} Nat Nat.hasLe (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (Finset.card.{u2} β t) n) (Finset.card.{u1} α s)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{0} Nat Nat.hasLe n (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)))))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (forall (a : α), (Membership.mem.{u1, u1} α (Finset.{u1} α) (Finset.instMembershipFinset.{u1} α) a s) -> (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) (f a) t)) -> (Finset.Nonempty.{u2} β t) -> (LE.le.{0} Nat instLENat (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat instMulNat) (Finset.card.{u2} β t) n) (Finset.card.{u1} α s)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{0} Nat instLENat n (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)))))
Case conversion may be inaccurate. Consider using '#align finset.exists_le_card_fiber_of_mul_le_card_of_maps_to Finset.exists_le_card_fiber_of_mul_le_card_of_maps_toₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: given a function between
finite sets `s` and `t` and a natural number `b` such that `card t * n ≤ card s`, there exists `y ∈
t` such that its preimage in `s` has at least `n` elements. See also
`finset.exists_lt_card_fiber_of_mul_lt_card_of_maps_to` for a stronger statement. -/
theorem exists_le_card_fiber_of_mul_le_card_of_maps_to (hf : ∀ a ∈ s, f a ∈ t) (ht : t.Nonempty)
    (hn : t.card * n ≤ s.card) : ∃ y ∈ t, n ≤ (s.filterₓ fun x => f x = y).card :=
  exists_le_card_fiber_of_nsmul_le_card_of_maps_to hf ht hn
#align finset.exists_le_card_fiber_of_mul_le_card_of_maps_to Finset.exists_le_card_fiber_of_mul_le_card_of_maps_to

/- warning: finset.exists_card_fiber_le_of_card_le_nsmul -> Finset.exists_card_fiber_le_of_card_le_nsmul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α s)) (SMul.smul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (OrderedCancelAddCommMonoid.toPartialOrder.{u3} M (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))) ((fun (a : Type) (b : Type.{u3}) [self : HasLiftT.{1, succ u3} a b] => self.0) Nat M (HasLiftT.mk.{1, succ u3} Nat M (CoeTCₓ.coe.{1, succ u3} Nat M (Nat.castCoe.{u3} M (AddMonoidWithOne.toNatCast.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))))))))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))) b)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {M : Type.{u3}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {b : M} [_inst_2 : LinearOrderedCommSemiring.{u3} M], (Finset.Nonempty.{u2} β t) -> (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α s)) (HSMul.hSMul.{0, u3, u3} Nat M M (instHSMul.{0, u3} Nat M (AddMonoid.SMul.{u3} M (AddMonoidWithOne.toAddMonoid.{u3} M (AddCommMonoidWithOne.toAddMonoidWithOne.{u3} M (NonAssocSemiring.toAddCommMonoidWithOne.{u3} M (Semiring.toNonAssocSemiring.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))))))) (Finset.card.{u2} β t) b)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{u3} M (Preorder.toLE.{u3} M (PartialOrder.toPreorder.{u3} M (StrictOrderedSemiring.toPartialOrder.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2))))) (Nat.cast.{u3} M (Semiring.toNatCast.{u3} M (StrictOrderedSemiring.toSemiring.{u3} M (LinearOrderedSemiring.toStrictOrderedSemiring.{u3} M (LinearOrderedCommSemiring.toLinearOrderedSemiring.{u3} M _inst_2)))) (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s))) b)))
Case conversion may be inaccurate. Consider using '#align finset.exists_card_fiber_le_of_card_le_nsmul Finset.exists_card_fiber_le_of_card_le_nsmulₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: given a function `f`, a
finite sets `s` and `t`, and a number `b` such that `card s ≤ card t • b`, there exists `y ∈ t` such
that its preimage in `s` has no more than `b` elements.
See also `finset.exists_card_fiber_lt_of_card_lt_nsmul` for a stronger statement. -/
theorem exists_card_fiber_le_of_card_le_nsmul (ht : t.Nonempty) (hb : ↑s.card ≤ t.card • b) :
    ∃ y ∈ t, ↑(s.filterₓ fun x => f x = y).card ≤ b :=
  by
  simp_rw [cast_card] at hb⊢
  refine'
    exists_sum_fiber_le_of_sum_fiber_nonneg_of_sum_le_nsmul
      (fun _ _ => sum_nonneg fun _ _ => zero_le_one) ht hb
#align finset.exists_card_fiber_le_of_card_le_nsmul Finset.exists_card_fiber_le_of_card_le_nsmul

/- warning: finset.exists_card_fiber_le_of_card_le_mul -> Finset.exists_card_fiber_le_of_card_le_mul is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (Finset.Nonempty.{u2} β t) -> (LE.le.{0} Nat Nat.hasLe (Finset.card.{u1} α s) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (Finset.card.{u2} β t) n)) -> (Exists.{succ u2} β (fun (y : β) => Exists.{0} (Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) (fun (H : Membership.Mem.{u2, u2} β (Finset.{u2} β) (Finset.hasMem.{u2} β) y t) => LE.le.{0} Nat Nat.hasLe (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)) n)))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : DecidableEq.{succ u2} β] {s : Finset.{u1} α} {t : Finset.{u2} β} {f : α -> β} {n : Nat}, (Finset.Nonempty.{u2} β t) -> (LE.le.{0} Nat instLENat (Finset.card.{u1} α s) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat instMulNat) (Finset.card.{u2} β t) n)) -> (Exists.{succ u2} β (fun (y : β) => And (Membership.mem.{u2, u2} β (Finset.{u2} β) (Finset.instMembershipFinset.{u2} β) y t) (LE.le.{0} Nat instLENat (Finset.card.{u1} α (Finset.filter.{u1} α (fun (x : α) => Eq.{succ u2} β (f x) y) (fun (a : α) => _inst_1 (f a) y) s)) n)))
Case conversion may be inaccurate. Consider using '#align finset.exists_card_fiber_le_of_card_le_mul Finset.exists_card_fiber_le_of_card_le_mulₓ'. -/
/-- The pigeonhole principle for finitely many pigeons counted by heads: given a function `f`, a
finite sets `s` in its domain, a finite set `t` in its codomain, and a natural number `n` such that
`card s ≤ card t * n`, there exists `y ∈ t` such that its preimage in `s` has no more than `n`
elements. See also `finset.exists_card_fiber_lt_of_card_lt_mul` for a stronger statement. -/
theorem exists_card_fiber_le_of_card_le_mul (ht : t.Nonempty) (hn : s.card ≤ t.card * n) :
    ∃ y ∈ t, (s.filterₓ fun x => f x = y).card ≤ n :=
  exists_card_fiber_le_of_card_le_nsmul ht hn
#align finset.exists_card_fiber_le_of_card_le_mul Finset.exists_card_fiber_le_of_card_le_mul

end Finset

namespace Fintype

open Finset

variable [Fintype α] [Fintype β] (f : α → β) {w : α → M} {b : M} {n : ℕ}

section

variable [LinearOrderedCancelAddCommMonoid M]

/-!
### The pigeonhole principles on `fintypes`s, pigeons counted by weight

In this section we specialize theorems from the previous section to the special case of functions
between `fintype`s and `s = univ`, `t = univ`. In this case the assumption `∀ x ∈ s, f x ∈ t` always
holds, so we have four theorems instead of eight. -/

#print Fintype.exists_lt_sum_fiber_of_nsmul_lt_sum /-
/-- The pigeonhole principle for finitely many pigeons of different weights, strict inequality
version: there is a pigeonhole with the total weight of pigeons in it greater than `b` provided that
the total number of pigeonholes times `b` is less than the total weight of all pigeons. -/
theorem exists_lt_sum_fiber_of_nsmul_lt_sum (hb : card β • b < ∑ x, w x) :
    ∃ y, b < ∑ x in univ.filterₓ fun x => f x = y, w x :=
  let ⟨y, _, hy⟩ := exists_lt_sum_fiber_of_maps_to_of_nsmul_lt_sum (fun _ _ => mem_univ _) hb
  ⟨y, hy⟩
#align fintype.exists_lt_sum_fiber_of_nsmul_lt_sum Fintype.exists_lt_sum_fiber_of_nsmul_lt_sum
-/

#print Fintype.exists_le_sum_fiber_of_nsmul_le_sum /-
/-- The pigeonhole principle for finitely many pigeons of different weights, non-strict inequality
version: there is a pigeonhole with the total weight of pigeons in it greater than or equal to `b`
provided that the total number of pigeonholes times `b` is less than or equal to the total weight of
all pigeons. -/
theorem exists_le_sum_fiber_of_nsmul_le_sum [Nonempty β] (hb : card β • b ≤ ∑ x, w x) :
    ∃ y, b ≤ ∑ x in univ.filterₓ fun x => f x = y, w x :=
  let ⟨y, _, hy⟩ :=
    exists_le_sum_fiber_of_maps_to_of_nsmul_le_sum (fun _ _ => mem_univ _) univ_nonempty hb
  ⟨y, hy⟩
#align fintype.exists_le_sum_fiber_of_nsmul_le_sum Fintype.exists_le_sum_fiber_of_nsmul_le_sum
-/

#print Fintype.exists_sum_fiber_lt_of_sum_lt_nsmul /-
/-- The pigeonhole principle for finitely many pigeons of different weights, strict inequality
version: there is a pigeonhole with the total weight of pigeons in it less than `b` provided that
the total number of pigeonholes times `b` is greater than the total weight of all pigeons. -/
theorem exists_sum_fiber_lt_of_sum_lt_nsmul (hb : (∑ x, w x) < card β • b) :
    ∃ y, (∑ x in univ.filterₓ fun x => f x = y, w x) < b :=
  @exists_lt_sum_fiber_of_nsmul_lt_sum α β Mᵒᵈ _ _ _ _ _ _ _ hb
#align fintype.exists_sum_fiber_lt_of_sum_lt_nsmul Fintype.exists_sum_fiber_lt_of_sum_lt_nsmul
-/

#print Fintype.exists_sum_fiber_le_of_sum_le_nsmul /-
/-- The pigeonhole principle for finitely many pigeons of different weights, non-strict inequality
version: there is a pigeonhole with the total weight of pigeons in it less than or equal to `b`
provided that the total number of pigeonholes times `b` is greater than or equal to the total weight
of all pigeons. -/
theorem exists_sum_fiber_le_of_sum_le_nsmul [Nonempty β] (hb : (∑ x, w x) ≤ card β • b) :
    ∃ y, (∑ x in univ.filterₓ fun x => f x = y, w x) ≤ b :=
  @exists_le_sum_fiber_of_nsmul_le_sum α β Mᵒᵈ _ _ _ _ _ _ _ _ hb
#align fintype.exists_sum_fiber_le_of_sum_le_nsmul Fintype.exists_sum_fiber_le_of_sum_le_nsmul
-/

end

variable [LinearOrderedCommSemiring M]

#print Fintype.exists_lt_card_fiber_of_nsmul_lt_card /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. There is a pigeonhole
with at least as many pigeons as the ceiling of the average number of pigeons across all
pigeonholes. -/
theorem exists_lt_card_fiber_of_nsmul_lt_card (hb : card β • b < card α) :
    ∃ y : β, b < (univ.filterₓ fun x => f x = y).card :=
  let ⟨y, _, h⟩ := exists_lt_card_fiber_of_nsmul_lt_card_of_maps_to (fun _ _ => mem_univ _) hb
  ⟨y, h⟩
#align fintype.exists_lt_card_fiber_of_nsmul_lt_card Fintype.exists_lt_card_fiber_of_nsmul_lt_card
-/

#print Fintype.exists_lt_card_fiber_of_mul_lt_card /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes.
There is a pigeonhole with at least as many pigeons as
the ceiling of the average number of pigeons across all pigeonholes.
("The maximum is at least the mean" specialized to integers.)

More formally, given a function `f` between finite types `α` and `β` and a number `n` such that
`card β * n < card α`, there exists an element `y : β` such that its preimage has more than `n`
elements. -/
theorem exists_lt_card_fiber_of_mul_lt_card (hn : card β * n < card α) :
    ∃ y : β, n < (univ.filterₓ fun x => f x = y).card :=
  exists_lt_card_fiber_of_nsmul_lt_card _ hn
#align fintype.exists_lt_card_fiber_of_mul_lt_card Fintype.exists_lt_card_fiber_of_mul_lt_card
-/

#print Fintype.exists_card_fiber_lt_of_card_lt_nsmul /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes. There is a pigeonhole
with at most as many pigeons as the floor of the average number of pigeons across all pigeonholes.
-/
theorem exists_card_fiber_lt_of_card_lt_nsmul (hb : ↑(card α) < card β • b) :
    ∃ y : β, ↑(univ.filterₓ fun x => f x = y).card < b :=
  let ⟨y, _, h⟩ := exists_card_fiber_lt_of_card_lt_nsmul hb
  ⟨y, h⟩
#align fintype.exists_card_fiber_lt_of_card_lt_nsmul Fintype.exists_card_fiber_lt_of_card_lt_nsmul
-/

#print Fintype.exists_card_fiber_lt_of_card_lt_mul /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes.
There is a pigeonhole with at most as many pigeons as
the floor of the average number of pigeons across all pigeonholes.
("The minimum is at most the mean" specialized to integers.)

More formally, given a function `f` between finite types `α` and `β` and a number `n` such that
`card α < card β * n`, there exists an element `y : β` such that its preimage has less than `n`
elements. -/
theorem exists_card_fiber_lt_of_card_lt_mul (hn : card α < card β * n) :
    ∃ y : β, (univ.filterₓ fun x => f x = y).card < n :=
  exists_card_fiber_lt_of_card_lt_nsmul _ hn
#align fintype.exists_card_fiber_lt_of_card_lt_mul Fintype.exists_card_fiber_lt_of_card_lt_mul
-/

#print Fintype.exists_le_card_fiber_of_nsmul_le_card /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes.  Given a function `f`
between finite types `α` and `β` and a number `b` such that `card β • b ≤ card α`, there exists an
element `y : β` such that its preimage has at least `b` elements.
See also `fintype.exists_lt_card_fiber_of_nsmul_lt_card` for a stronger statement. -/
theorem exists_le_card_fiber_of_nsmul_le_card [Nonempty β] (hb : card β • b ≤ card α) :
    ∃ y : β, b ≤ (univ.filterₓ fun x => f x = y).card :=
  let ⟨y, _, h⟩ :=
    exists_le_card_fiber_of_nsmul_le_card_of_maps_to (fun _ _ => mem_univ _) univ_nonempty hb
  ⟨y, h⟩
#align fintype.exists_le_card_fiber_of_nsmul_le_card Fintype.exists_le_card_fiber_of_nsmul_le_card
-/

#print Fintype.exists_le_card_fiber_of_mul_le_card /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes.  Given a function `f`
between finite types `α` and `β` and a number `n` such that `card β * n ≤ card α`, there exists an
element `y : β` such that its preimage has at least `n` elements. See also
`fintype.exists_lt_card_fiber_of_mul_lt_card` for a stronger statement. -/
theorem exists_le_card_fiber_of_mul_le_card [Nonempty β] (hn : card β * n ≤ card α) :
    ∃ y : β, n ≤ (univ.filterₓ fun x => f x = y).card :=
  exists_le_card_fiber_of_nsmul_le_card _ hn
#align fintype.exists_le_card_fiber_of_mul_le_card Fintype.exists_le_card_fiber_of_mul_le_card
-/

#print Fintype.exists_card_fiber_le_of_card_le_nsmul /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes.  Given a function `f`
between finite types `α` and `β` and a number `b` such that `card α ≤ card β • b`, there exists an
element `y : β` such that its preimage has at most `b` elements.
See also `fintype.exists_card_fiber_lt_of_card_lt_nsmul` for a stronger statement. -/
theorem exists_card_fiber_le_of_card_le_nsmul [Nonempty β] (hb : ↑(card α) ≤ card β • b) :
    ∃ y : β, ↑(univ.filterₓ fun x => f x = y).card ≤ b :=
  let ⟨y, _, h⟩ := exists_card_fiber_le_of_card_le_nsmul univ_nonempty hb
  ⟨y, h⟩
#align fintype.exists_card_fiber_le_of_card_le_nsmul Fintype.exists_card_fiber_le_of_card_le_nsmul
-/

#print Fintype.exists_card_fiber_le_of_card_le_mul /-
/-- The strong pigeonhole principle for finitely many pigeons and pigeonholes.  Given a function `f`
between finite types `α` and `β` and a number `n` such that `card α ≤ card β * n`, there exists an
element `y : β` such that its preimage has at most `n` elements. See also
`fintype.exists_card_fiber_lt_of_card_lt_mul` for a stronger statement. -/
theorem exists_card_fiber_le_of_card_le_mul [Nonempty β] (hn : card α ≤ card β * n) :
    ∃ y : β, (univ.filterₓ fun x => f x = y).card ≤ n :=
  exists_card_fiber_le_of_card_le_nsmul _ hn
#align fintype.exists_card_fiber_le_of_card_le_mul Fintype.exists_card_fiber_le_of_card_le_mul
-/

end Fintype

namespace Nat

open Set

/- warning: nat.exists_lt_modeq_of_infinite -> Nat.exists_lt_modEq_of_infinite is a dubious translation:
lean 3 declaration is
  forall {s : Set.{0} Nat}, (Set.Infinite.{0} Nat s) -> (forall {k : Nat}, (LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) k) -> (Exists.{1} Nat (fun (m : Nat) => Exists.{0} (Membership.Mem.{0, 0} Nat (Set.{0} Nat) (Set.hasMem.{0} Nat) m s) (fun (H : Membership.Mem.{0, 0} Nat (Set.{0} Nat) (Set.hasMem.{0} Nat) m s) => Exists.{1} Nat (fun (n : Nat) => Exists.{0} (Membership.Mem.{0, 0} Nat (Set.{0} Nat) (Set.hasMem.{0} Nat) n s) (fun (H : Membership.Mem.{0, 0} Nat (Set.{0} Nat) (Set.hasMem.{0} Nat) n s) => And (LT.lt.{0} Nat Nat.hasLt m n) (Nat.ModEq k m n)))))))
but is expected to have type
  forall {s : Set.{0} Nat}, (Set.Infinite.{0} Nat s) -> (forall {k : Nat}, (LT.lt.{0} Nat instLTNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) k) -> (Exists.{1} Nat (fun (m : Nat) => And (Membership.mem.{0, 0} Nat (Set.{0} Nat) (Set.instMembershipSet.{0} Nat) m s) (Exists.{1} Nat (fun (n : Nat) => And (Membership.mem.{0, 0} Nat (Set.{0} Nat) (Set.instMembershipSet.{0} Nat) n s) (And (LT.lt.{0} Nat instLTNat m n) (Nat.ModEq k m n)))))))
Case conversion may be inaccurate. Consider using '#align nat.exists_lt_modeq_of_infinite Nat.exists_lt_modEq_of_infiniteₓ'. -/
/-- If `s` is an infinite set of natural numbers and `k > 0`, then `s` contains two elements `m < n`
that are equal mod `k`. -/
theorem exists_lt_modEq_of_infinite {s : Set ℕ} (hs : s.Infinite) {k : ℕ} (hk : 0 < k) :
    ∃ m ∈ s, ∃ n ∈ s, m < n ∧ m ≡ n [MOD k] :=
  (hs.exists_lt_map_eq_of_mapsTo fun n _ => show n % k ∈ Iio k from Nat.mod_lt n hk) <|
    finite_lt_nat k
#align nat.exists_lt_modeq_of_infinite Nat.exists_lt_modEq_of_infinite

end Nat


import starkware.cairo.lean.semantics.cpu

variables {F : Type*} [field F]

-- number of 16-bit range-checked values
variable {rc16_len : ℕ}

-- number of 128-bit range-checked values
variables {rc_len : ℕ}

-- this is public data
variable {initial_rc_addr : F}

-- this comes from range check constraints
variable {rc16_val : fin rc16_len → F}

-- these come from memory constraints
variable {rc_addr : fin rc_len → F}  -- rc_builtin__mem__addr
variable {rc_val  : fin rc_len → F}  -- rc_builtin__mem__value

-- map eight rc16 values to one rc value
variable {rc_to_rc16 : fin rc_len → fin 8 → fin rc16_len}

-- this comes from range check constraints
variable h_rc16_val : ∀ i : fin rc16_len, ∃ k : ℕ, k < 2^16 ∧ rc16_val i = ↑k

-- these are the range check builtin constraints

variable h_rc_init_addr : ∀ h : 0 < rc_len, rc_addr ⟨0, h⟩ = initial_rc_addr

variable h_rc_addr_step : ∀ i : ℕ, ∀ h : i.succ < rc_len,
rc_addr ⟨i.succ, h⟩ = rc_addr ⟨i, (nat.lt_succ_self _).trans h⟩  + 1

variable h_rc_value : ∀ i : fin rc_len,
  rc_val i = (((((((rc16_val (rc_to_rc16 i 0))
    * 2^16 + rc16_val (rc_to_rc16 i 1))
    * 2^16 + rc16_val (rc_to_rc16 i 2))
    * 2^16 + rc16_val (rc_to_rc16 i 3))
    * 2^16 + rc16_val (rc_to_rc16 i 4))
    * 2^16 + rc16_val (rc_to_rc16 i 5))
    * 2^16 + rc16_val (rc_to_rc16 i 6))
    * 2^16 + rc16_val (rc_to_rc16 i 7)

section
include h_rc_init_addr h_rc_addr_step

theorem rc_addr_eq (i : fin rc_len) : rc_addr i = initial_rc_addr + i :=
begin
  cases i with i h,
  induction i with i ih,
  { simp [h_rc_init_addr] },
  rw [h_rc_addr_step i h, ih ((nat.lt_succ_self _).trans h), add_assoc],
  simp
end
end

section
include h_rc16_val h_rc_value

theorem rc_val_checked (i : fin rc_len) : ∃ k : ℕ, k < 2^128 ∧ rc_val i = ↑k :=
have rc_val_aux : ∀ {n : ℕ} (h : n < 2^16), n ≤ 2^16-1 :=
  begin
    intros n h,
    apply nat.le_of_succ_le_succ,
    apply le_trans (nat.succ_le_of_lt h),
    norm_num
  end,
begin
  rw [h_rc_value],
  rcases h_rc16_val (rc_to_rc16 i 0) with ⟨k0, k0_lt, k0eq⟩, rw k0eq,
  rcases h_rc16_val (rc_to_rc16 i 1) with ⟨k1, k1_lt, k1eq⟩, rw k1eq,
  rcases h_rc16_val (rc_to_rc16 i 2) with ⟨k2, k2_lt, k2eq⟩, rw k2eq,
  rcases h_rc16_val (rc_to_rc16 i 3) with ⟨k3, k3_lt, k3eq⟩, rw k3eq,
  rcases h_rc16_val (rc_to_rc16 i 4) with ⟨k4, k4_lt, k4eq⟩, rw k4eq,
  rcases h_rc16_val (rc_to_rc16 i 5) with ⟨k5, k5_lt, k5eq⟩, rw k5eq,
  rcases h_rc16_val (rc_to_rc16 i 6) with ⟨k6, k6_lt, k6eq⟩, rw k6eq,
  rcases h_rc16_val (rc_to_rc16 i 7) with ⟨k7, k7_lt, k7eq⟩, rw k7eq,
  norm_cast,
  refine ⟨_, _, rfl⟩,
  have : ((((((((2^16 - 1)
    * 2^16 + (2^16 - 1))
    * 2^16 + (2^16 - 1))
    * 2^16 + (2^16 - 1))
    * 2^16 + (2^16 - 1))
    * 2^16 + (2^16 - 1))
    * 2^16 + (2^16 - 1))
    * 2^16 + (2^16 - 1)) < 2^128, by norm_num,
  apply lt_of_le_of_lt _ this,
  apply add_le_add _ (rc_val_aux k7_lt),
  apply nat.mul_le_mul_right,
  apply add_le_add _ (rc_val_aux k6_lt),
  apply nat.mul_le_mul_right,
  apply add_le_add _ (rc_val_aux k5_lt),
  apply nat.mul_le_mul_right,
  apply add_le_add _ (rc_val_aux k4_lt),
  apply nat.mul_le_mul_right,
  apply add_le_add _ (rc_val_aux k3_lt),
  apply nat.mul_le_mul_right,
  apply add_le_add _ (rc_val_aux k2_lt),
  apply nat.mul_le_mul_right,
  apply add_le_add _ (rc_val_aux k1_lt),
  apply nat.mul_le_mul_right,
  apply rc_val_aux k0_lt
end

end