/-
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Floris van Doorn, Leonardo de Moura
-/
prelude
import init.core

notation `ℕ` := Nat

namespace Nat

inductive lessThanOrEqual (a : ℕ) : ℕ → Prop
| refl : lessThanOrEqual a
| step : Π {b}, lessThanOrEqual b → lessThanOrEqual (succ b)

@[elabAsEliminator]
theorem lessThanOrEqual.ndrec  {a : Nat} {C : Nat → Prop} (m₁ : C a) (m₂ : ∀ (b : Nat), lessThanOrEqual a b → C b → C (succ b)) {b : ℕ} (h : lessThanOrEqual a b) : C b :=
@lessThanOrEqual.rec a (λ b _, C b) m₁ m₂ b h

@[elabAsEliminator]
theorem lessThanOrEqual.ndrecOn {a : Nat} {C : Nat → Prop} {b : ℕ} (h : lessThanOrEqual a b) (m₁ : C a) (m₂ : ∀ (b : Nat), lessThanOrEqual a b → C b → C (succ b)) : C b :=
@lessThanOrEqual.rec a (λ b _, C b) m₁ m₂ b h

instance : HasLessEq ℕ :=
⟨Nat.lessThanOrEqual⟩

@[reducible] protected def le (n m : ℕ) := Nat.lessThanOrEqual n m
@[reducible] protected def lt (n m : ℕ) := Nat.lessThanOrEqual (succ n) m

set_option codegen false


instance : HasLess ℕ :=
⟨Nat.lt⟩

def pred : ℕ → ℕ
| 0     := 0
| (a+1) := a

protected def sub : ℕ → ℕ → ℕ
| a 0     := a
| a (b+1) := pred (sub a b)

protected def mul : Nat → Nat → Nat
| a 0     := 0
| a (b+1) := (mul a b) + a

instance : HasSub ℕ :=
⟨Nat.sub⟩

instance : HasMul ℕ :=
⟨Nat.mul⟩

def hasDecEq : Π a b : Nat, Decidable (a = b)
| zero     zero     := isTrue rfl
| (succ x) zero     := isFalse (λ h, Nat.noConfusion h)
| zero     (succ y) := isFalse (λ h, Nat.noConfusion h)
| (succ x) (succ y) :=
    match hasDecEq x y with
    | isTrue xeqy := isTrue (xeqy ▸ Eq.refl (succ x))
    | isFalse xney := isFalse (λ h, Nat.noConfusion h (λ xeqy, absurd xeqy xney))

instance : DecidableEq ℕ :=
{decEq := hasDecEq}

def {u} repeat {α : Type u} (f : ℕ → α → α) : ℕ → α → α
| 0         a := a
| (succ n)  a := f n (repeat n a)

theorem natZeroEqZero : Nat.zero = 0 :=
rfl

/- properties of inequality -/

protected def leRefl : ∀ a : ℕ, a ≤ a :=
lessThanOrEqual.refl

theorem leSucc (n : ℕ) : n ≤ succ n :=
lessThanOrEqual.step (Nat.leRefl n)

theorem succLeSucc {n m : ℕ} : n ≤ m → succ n ≤ succ m :=
λ h, lessThanOrEqual.ndrec (Nat.leRefl (succ n)) (λ a b, lessThanOrEqual.step) h

theorem zeroLe : ∀ (n : ℕ), 0 ≤ n
| 0     := Nat.leRefl 0
| (n+1) := lessThanOrEqual.step (zeroLe n)

theorem zeroLtSucc (n : ℕ) : 0 < succ n :=
succLeSucc (zeroLe n)

def succPos := zeroLtSucc

theorem notSuccLeZero : ∀ (n : ℕ), succ n ≤ 0 → False
.

theorem notLtZero (a : ℕ) : ¬ a < 0 := notSuccLeZero a

theorem predLePred {n m : ℕ} : n ≤ m → pred n ≤ pred m :=
λ h, lessThanOrEqual.ndrecOn h
  (Nat.leRefl (pred n))
  (λ n, Nat.rec (λ a b, b) (λ a b c, lessThanOrEqual.step) n)

theorem leOfSuccLeSucc {n m : ℕ} : succ n ≤ succ m → n ≤ m :=
predLePred

instance decidableLe : ∀ a b : ℕ, Decidable (a ≤ b)
| 0     b     := isTrue (zeroLe b)
| (a+1) 0     := isFalse (notSuccLeZero a)
| (a+1) (b+1) :=
  match decidableLe a b with
  | isTrue h  := isTrue (succLeSucc h)
  | isFalse h := isFalse (λ a, h (leOfSuccLeSucc a))

instance decidableLt : ∀ a b : ℕ, Decidable (a < b) :=
λ a b, Nat.decidableLe (succ a) b

protected theorem eqOrLtOfLe {a b : ℕ} (h : a ≤ b) : a = b ∨ a < b :=
lessThanOrEqual.casesOn h (Or.inl rfl) (λ n h, Or.inr (succLeSucc h))

theorem ltSuccOfLe {a b : ℕ} : a ≤ b → a < succ b :=
succLeSucc

theorem succSubSuccEqSub (a b : ℕ) : succ a - succ b = a - b :=
Nat.recOn b
  (show succ a - succ zero = a - zero, from (Eq.refl (succ a - succ zero)))
  (λ b, congrArg pred)

theorem notSuccLeSelf : ∀ n : ℕ, ¬succ n ≤ n :=
λ n, Nat.rec (notSuccLeZero 0) (λ a b c, b (leOfSuccLeSucc c)) n

protected theorem ltIrrefl (n : ℕ) : ¬n < n :=
notSuccLeSelf n

protected theorem leTrans {n m k : ℕ} (h1 : n ≤ m) : m ≤ k → n ≤ k :=
lessThanOrEqual.ndrec h1 (λ p h2, lessThanOrEqual.step)

theorem predLe : ∀ (n : ℕ), pred n ≤ n
| 0        := lessThanOrEqual.refl 0
| (succ a) := lessThanOrEqual.step (lessThanOrEqual.refl a)

theorem predLt : ∀ {n : ℕ}, n ≠ 0 → pred n < n
| 0        h := absurd rfl h
| (succ a) h := ltSuccOfLe (lessThanOrEqual.refl _)

theorem subLe (a b : ℕ) : a - b ≤ a :=
Nat.recOn b (Nat.leRefl (a - 0)) (λ b₁, Nat.leTrans (predLe (a - b₁)))

theorem subLt : ∀ {a b : ℕ}, 0 < a → 0 < b → a - b < a
| 0     b     h1 h2 := absurd h1 (Nat.ltIrrefl 0)
| (a+1) 0     h1 h2 := absurd h2 (Nat.ltIrrefl 0)
| (a+1) (b+1) h1 h2 :=
  Eq.symm (succSubSuccEqSub a b) ▸
    show a - b < succ a, from
    ltSuccOfLe (subLe a b)

protected theorem ltOfLtOfLe {n m k : ℕ} : n < m → m ≤ k → n < k :=
Nat.leTrans

end Nat
