/- Clara L"oh 2021 -/

import tactic   -- standard proof tactics
open finset     -- for range operator
open_locale big_operators -- to enable ∑ notation

open classical  -- we want to work in classical logic

/-
# A simple induction proof
-/

-- we define geometric sums (at base 2) ...
def geometric_sum
  : nat → nat
| 0            := 1 
| (nat.succ n) := geometric_sum n + 2^(n+1)

-- ... and show how they can be computed
lemma geometric_sum_eval
      (n : nat)
    : geometric_sum n = 2^(n+1) - 1
:= 
begin
  -- we prove this claim by induction (over the natural number argument n);
  -- here, m is the variable used in the induction step 
  -- and ind_hyp is the induction hypothesis used in the induction step
  induction n with m ind_hyp,

  -- base case: 0
  case nat.zero : {simp[geometric_sum]},

  -- induction step: m -> m+1
  case nat.succ : 
  begin
    calc geometric_sum (m+1) = geometric_sum m + 2^(m+1) : by {simp[geometric_sum]}
                        ...  = 2^(m+1) - 1 + 2^(m+1)     : by {simp[ind_hyp]}
                        ...  = 2^(m+1) + 2^(m+1) - 1     : by {omega}
                        ...  = 2 * 2^(m+1) - 1           : by {ring}
                        ...  = 2^(m+2) - 1               : by {ring},
  end
end      

-- computing some examples:
#eval geometric_sum 0
#eval geometric_sum 5


/-
# Using the ∑ notation
-/

-- and another simple sum, 
-- using the sum operator from mathlib (big_operators)
def one_sum 
  : nat → nat
:= λ n : nat, 
   ∑ (i : nat) in range n, 1

lemma one_sum_eval
      (n : nat)
    : (one_sum n = n)
:=
begin
  -- we prove this claim by induction (over the natural number argument n)
  induction n with m ind_hyp,

  -- base case: 0 
  case nat.zero : {simp[one_sum]},

  -- induction step: m -> m+1
  case nat.succ : 
  begin
    calc one_sum (m+1) = ∑ (i : nat) in range (m+1), 1   : by {simp[one_sum]}
                   ... = (∑ (i : nat) in range m, 1) + 1 : by {simp}
                   ... = m + 1                           : by {simp[ind_hyp]},
  end
  /-
  unfold one_sum,
  -- found by library_search :)
  by {exact sum_range_induction (λ (k : ℕ), 1) (λ (n : ℕ), n) rfl (congr_fun rfl) n},
  -/  
end      

