Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prove mathematical induction formulae in LEAN theorem prover?

Can anyone help me understand how to write the proof of a simple result that can be easily obtained by induction, for example the formula for the sum of the first n natural numbers: 1+2+...+n = n(n+1)/2, using the LEAN theorem prover?

like image 839
Vox Avatar asked Dec 05 '25 18:12

Vox


2 Answers

Here is my proof. You'll need mathlib for it to work.

import algebra.big_operators tactic.ring

open finset

example (n : ℕ) : 2 * (range (n + 1)).sum id = n * (n + 1) :=
begin
  induction n with n ih,
  { refl },
  { rw [sum_range_succ, mul_add, ih, id.def, nat.succ_eq_add_one],
    ring }
end

range (n + 1) is the set of natural numbers less than n + 1, i.e. 0 to n.

I used the finset.sum function. If s is a finset and f is a function, then s.sum f is $\sum_{x \in s} f(x)$.

The induction tactic does induction. There are then two cases. The case n = 0 can be done with refl since this is nothing more than a computation.

The inductive step can be done with rw. Using a VSCode you can click after each comma in my proof to see what each rw does. This gets it into a form that the ring tactic will solve.

like image 117
Christopher Hughes Avatar answered Dec 10 '25 12:12

Christopher Hughes


I was just going through this exercise while trying to learn Lean 4. Here is my solution (so far, likely lots of room for improvement):

import Mathlib.Tactic.Ring

-- summing 1 + 2 + ... + n
def sum_first_n(n: Nat) : Nat :=
  match n with
  | 0 => 0
  | m + 1 => m + 1 + sum_first_n m

-- summing 1 + 2 + ... + n == n * (n + 1) / 2
theorem sum_first_n_eq_my_definition(n: Nat) : sum_first_n n = n * (n + 1) / 2 := by
  induction n
  . simp [sum_first_n]
  case succ m ih =>
    simp [sum_first_n]
    rw [ih]
    ring_nf
    rw [(by ring: m * 3 = m * 2 + m)]
    rw [(by ring: 2 + (m * 2 + m) = 2 * (m + 1) + m)]
    rw [Nat.add_assoc (2 * (m + 1)) _ _, Nat.add_comm (2 * (m + 1)) _]
    rw [Nat.add_mul_div_left _ _ (by decide : (0 < 2))]
    ring

This should work for the range and sum definition (not the custom sum function), but I am having hard time unrolling the foldr:

theorem sum_n_plus_one(n: Nat) : Nat.sum (List.range (n + 1)) = n + Nat.sum (List.range n) := by
  sorry

theorem sum_first_n_eq(n: Nat) : Nat.sum (List.range (n + 1)) = n * (n + 1) / 2 := by
  induction n
  case zero =>
    simp [Nat.sum, List.range, List.foldr]
  case succ m ih =>
    rw [sum_n_plus_one, ih]
    ring_nf
    rw [(by ring: m * 3 = m * 2 + m)]
    rw [(by ring: 2 + (m * 2 + m) = 2 * (m + 1) + m)]
    rw [Nat.add_assoc (2 * (m + 1)) _ _, Nat.add_comm (2 * (m + 1)) _]
    rw [Nat.add_mul_div_left _ _ (by decide : (0 < 2))]
    ring
like image 36
Rado Avatar answered Dec 10 '25 14:12

Rado



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!