induction
Summary
The induction tactic will turn a goal of the form ⊢ P n (with P a predicate on naturals, and n a natural) into two goals ⊢ P 0 and ⊢ ∀ d, P d → P d.succ.
Overview
The induction tactic does exactly what you think it will do; it’s a tactic which reduces a goal which depends on a natural to two goals, the base case (always zero, in Lean) and the step case. In computer science it is very common to see a lot of other so-called inductive types (for example list and expr) and the induction tactic can get quite a lot of use; however in this course we only ever use induction on naturals.
Example
We show \(\sum_{i=0}^{n-1}i^2=n(n-1)(2n-1)/6\) by induction on \(n\).
import tactic
open_locale big_operators -- ∑ notation
open finset -- so I can say `range n` for the finite set `{0,1,2,...,n-1}`
-- sum from i = 0 to n - 1 of i^2 is n(n-1)(2n-1)/6
-- note that I immediately coerce into rationals in the statement to get the correct subtraction and
-- division (natural number subtraction and division are pathological functions)
example (n : ℕ) : ∑ i in range n, (i : ℚ)^2 = n * (n - 1) * (2 * n - 1) / 6 :=
begin
induction n with d hd,
{ -- base case says that an empty sum is zero times something, and this sort of goal
-- is perfect for the simplifier
simp, },
{ -- inductive step
rw finset.sum_range_succ, -- the lemma saying
-- `∑ i in range (n.succ), f i = (∑ i in range n, f i) + f n`
rw hd, -- the inductive hypothesis
simp, -- change `d.succ` into `d + 1`
ring,
}
end
Details
The definition of the natural numbers in Lean is this:
inductive nat
| zero : nat
| succ (n : nat) : nat
When this code is run, four new objects are created: the type nat, the term nat.zero, the function succ : nat → nat and the recursor for the naturals, a statement automatically generated from the definition and which can be described as saying that to do something for all naturals, you only have to do it for zero and succ n, and in the succ n case you can assume you already did it for n. The induction tactic applies this recursor and then does some tidying up. This is why you end up with goals containing n.succ rather than the more mathematically natural n + 1. In the example above I use simp to change n.succ to n + 1 (and also to push casts as far in as possible).