\import Arith.Fin
\import Arith.Nat
\import Data.Fin
\import Data.Or
\import Equiv
\import Function
\import Function.Meta ($)
\import Logic
\import Logic.Meta
\import Order.LinearOrder
\import Order.StrictOrder
\import Paths
\import Set
\import Set.Fin
\import Set.Fin.DFin
\open FinLinearOrder
\class PigeonholeSet \extends BaseSet {
| pigeonhole (f : Nat -> E) : ∃ (i j : Nat) (i /= j) (f i = f j)
\lemma pigeonhole< (f : Nat -> E) : ∃ (i j : Nat) (i < j) (f i = f j)
=> TruncP.map (pigeonhole f) \lam t => \case LinearOrder.trichotomy t.1 t.2 \with {
| less c => (t.1, t.2, c, t.4)
| equals c => absurd (t.3 c)
| greater c => (t.2, t.1, c, inv t.4)
}
\lemma isEquiv (f : E -> E) (inj : isInj f) : Equiv f
=> isDFin.isEquiv (isDFin.fromPigeonhole \this) f inj
}
\class BoundedPigeonholeSet \extends PigeonholeSet {
| finCard : Nat
| boundedPigeonhole (f : Fin (suc finCard) -> E) : ∃ (i j : Fin (suc finCard)) (i /= j) (f i = f j)
| pigeonhole f => TruncP.map (boundedPigeonhole (\lam j => f j)) \lam t => (t.1, t.2, fin_nat_/= t.3, t.4)
\lemma boundedPigeonhole< (f : Fin (suc finCard) -> E) : ∃ (i j : Fin (suc finCard)) (i < j) (f i = f j)
=> TruncP.map (boundedPigeonhole f) \lam t => \case LinearOrder.trichotomy t.1 t.2 \with {
| less c => (t.1, t.2, c, t.4)
| equals c => absurd (t.3 c)
| greater c => (t.2, t.1, c, inv t.4)
}
}
\lemma pigeonhole-surj (A : BoundedPigeonholeSet) {B : \Set} (f : A -> B) (s : isSurj f) : BoundedPigeonholeSet B A.finCard \cowith
| boundedPigeonhole g =>\have | (inP t) => FinSet.finiteAC (\lam j => s (g j))
| (inP r) => boundedPigeonhole (\lam j => (t j).1)
\in inP (r.1, r.2, r.3, inv (t r.1).2 *> pmap f r.4 *> (t r.2).2)
\lemma pigeonhole-fin {n m : Nat} (f : Fin m -> Fin n) (p : n < m) : ∃ (i j : Fin m) (i /= j) (f i = f j)
=> aux f \lam inj => <-irreflexive $ p <∘l FinSet.FinCardInj f inj
\where {
\lemma search-pair {n : Nat} {A : DecSet} (f : Fin n -> A) : Dec (∃ (i j : Fin n) (i /= j) (f i = f j))
=> \have t i : Dec (∃ (j : Fin n) (i /= j) (f i = f j)) => \case FinSet.searchFin (\lam j => \Sigma (i /= j) (f i = f j)) (\lam j => decide) \with {
| inl (j,p,_) => yes (inP (j, p.1, p.2))
| inr q => no \lam (inP (j, s, p)) => q j (s,p)
}
\in \case FinSet.searchFin _ t \with {
| inl (i,p,_) => yes $ TruncP.map p (\lam q => (i, q.1, q.2, q.3))
| inr q => no \lam (inP (i,j,e,p)) => q i (inP (j, e, p))
}
\lemma aux {n : Nat} {A : DecSet} (f : Fin n -> A) (p : Not (isInj f)) : ∃ (i j : Fin n) (i /= j) (f i = f j)
=> \case search-pair f \with {
| yes e => e
| no q => absurd $ p \lam {i} {j} p => \case decideEq i j \with {
| yes e => e
| no r => absurd $ q $ inP (i, j, r, p)
}
}
}