/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Chris Hughes, Floris van Doorn
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.nat.basic
import Mathlib.PostPort

namespace Mathlib

/-!
# The factorial function

-/

namespace nat

/-- `nat.factorial n` is the factorial of `n`. -/
@[simp] def factorial : ℕ → ℕ := sorry

@[simp] theorem factorial_zero : factorial 0 = factorial 1 := rfl

@[simp] theorem factorial_succ (n : ℕ) : factorial (Nat.succ n) = Nat.succ n * factorial n := rfl

@[simp] theorem factorial_one : factorial 1 = 1 := rfl

theorem mul_factorial_pred {n : ℕ} (hn : 0 < n) : n * factorial (n - 1) = factorial n :=
  nat.sub_add_cancel hn ▸ rfl

theorem factorial_pos (n : ℕ) : 0 < factorial n := sorry

theorem factorial_ne_zero (n : ℕ) : factorial n ≠ 0 := ne_of_gt (factorial_pos n)

theorem factorial_dvd_factorial {m : ℕ} {n : ℕ} (h : m ≤ n) : factorial m ∣ factorial n := sorry

theorem dvd_factorial {m : ℕ} {n : ℕ} : 0 < m → m ≤ n → m ∣ factorial n := sorry

theorem factorial_le {m : ℕ} {n : ℕ} (h : m ≤ n) : factorial m ≤ factorial n :=
  le_of_dvd (factorial_pos n) (factorial_dvd_factorial h)

theorem factorial_mul_pow_le_factorial {m : ℕ} {n : ℕ} :
    factorial m * Nat.succ m ^ n ≤ factorial (m + n) :=
  sorry

theorem monotone_factorial : monotone factorial := fun (n m : ℕ) => factorial_le

theorem factorial_lt {m : ℕ} {n : ℕ} (h0 : 0 < n) : factorial n < factorial m ↔ n < m := sorry

theorem one_lt_factorial {n : ℕ} : 1 < factorial n ↔ 1 < n := sorry

theorem factorial_eq_one {n : ℕ} : factorial n = 1 ↔ n ≤ 1 := sorry

theorem factorial_inj {m : ℕ} {n : ℕ} (h0 : 1 < factorial n) : factorial n = factorial m ↔ n = m :=
  sorry

theorem self_le_factorial (n : ℕ) : n ≤ factorial n := sorry

end Mathlib


import data.nat.choose

open_locale big_operators
lemma sum_n_choose (n : ℕ) : ∑ k in finset.range n, k = n.choose 2 :=
begin
  sorry
end

lemma imo_2019_qA3 (f : ℤ → ℤ) (hf : ∀ a b, f(2*a) + 2*f(b) = f(f(a + b))) :
 f = 0 ∨ ∃ c : ℤ, ∀ x, f x = 2*x + c := sorry


import Lean4_filters.Lattice.CompleteLattice

variable {α : Type u}

instance : CompleteLattice (Set α) := {
  top := Set.univ
  leTop := λ s x hx => True.intro
  bot := Set.empty
  botLe := λ s x hx => False.elim hx
  supr := λ C x => ∃ s, s ∈ C ∧ x ∈ s
  leSupr := λ C s hsC x hxs => ⟨s, hsC, hxs⟩
  suprLe := λ C s h1 x ⟨t, htC, hxt⟩ => h1 t htC hxt
  infi := λ C x => ∀ s, s ∈ C → x ∈ s
  infiLe := λ X s hsX a h => h _ hsX
  leInfi := λ C s h a has t htC => h t htC has
}

example : CompleteLattice (Set α) := {
  top := Set.univ
  leTop := by
    intros s x hx;
    trivial;
  bot := Set.empty
  botLe := by
    intros s x hx;
    cases hx;
  supr := λ C x => ∃ s, s ∈ C ∧ x ∈ s
  leSupr := by
    intros C s hsC x hxs;
    exact ⟨s, hsC, hxs⟩;
  suprLe := by
    intros C s h1 x h;
    let ⟨t, htC, hxt⟩ := h;
    exact h1 t htC hxt;
  infi := λ C x => ∀ s, s ∈ C → x ∈ s
  infiLe := by
    intro X s hsX a h;
    exact h _ hsX;
  leInfi := by
    intro C s h a has t htC;
    exact h t htC has
}