Skip to main content
added 1306 characters in body
Source Link
Kyle Miller
  • 541
  • 3
  • 10
 
import data.nat.choose.basic
import data.nat.fib
import data.list.defs
import data.list.nat_antidiagonal

open function

lemma list.sum_map_add {ι α : Type*} [add_comm_monoid α] {f g : ι → α} (l : list ι) :
  (l.map (λ x, f x + g x)).sum = (l.map f).sum + (l.map g).sum  :=
list.sum_hom₂ _ _ add_add_add_comm (add_zero _) _ _

lemma list.nat.antidiagonal_succ' (n : ℕ) :
  list.nat.antidiagonal (n + 1) =
  ((list.nat.antidiagonal n).map (prod.map id nat.succ)) ++ [(n + 1, 0)] :=
begin
  simp only [list.nat.antidiagonal, list.range_succ, add_tsub_cancel_left, list.map_append,
    list.append_assoc, tsub_self, list.singleton_append, list.map_map, list.map],
  congr' 1,
  apply list.map_congr,
  simp [le_of_lt, nat.succ_eq_add_one, nat.sub_add_comm] { contextual := tt },
end

lemma list.nat.antidiagonal_succ_succ' (n : ℕ) :
  list.nat.antidiagonal (n + 2) =
  (0, n + 2) :: ((list.nat.antidiagonal n).map (prod.map nat.succ nat.succ)) ++ [(n + 2, 0)] :=
begin
  induction n with n ih,
  { refl, },
  { rw [nat.succ_add, list.nat.antidiagonal_succ, ih],
    simpa, },
end

theorem fib_eq_sum_choose_antidiagonal (n : ℕ) :
  (n + 1).fib = ((list.nat.antidiagonal n).map (uncurry nat.choose)).sum :=
begin
  induction n using nat.two_step_induction with n h0 h1,
  { refl, },
  { refl, },
  rw [nat.fib_add_two, h0, h1, list.nat.antidiagonal_succ_succ', list.nat.antidiagonal_succ'],
  simpa [←add_assoc, ←list.sum_map_add, uncurry, ←nat.choose_succ_succ],
end
```

All that said, using lists isn't the usual way you work with sums in mathlib. Instead, you work with finset and the "big operators." Contingent on the mathlib PR for manipulating antidiagonals, the theorem ends up being just this:

import data.finset.nat_antidiagonal
import data.nat.fib
import algebra.big_operators.basic

open_locale big_operators
open finset

theorem fib_eq_sum_choose_antidiagonal (n : ℕ) :
  (n + 1).fib = ∑ p in nat.antidiagonal n, nat.choose p.1 p.2 :=
begin
  induction n using nat.two_step_induction with n h0 h1,
  { refl, },
  { refl, },
  rw [nat.fib_add_two, h0, h1, nat.antidiagonal_succ_succ', nat.antidiagonal_succ'],
  simp [nat.choose_succ_succ, add_assoc, add_left_comm, sum_add_distrib],
end

After doing the basic manipulations you described in your proof outline, simp ends up doing the heavy lifting. An interesting thing about this tactic is that it's able to put things into a normal form even if the lemmas can potentially form rewrite loops. The add_assoc and add_left_comm lemmas here are giving simp the capability of sorting the additions, as a weak kind of ring. (Usually you'd include add_comm, too, but it wasn't necessary here.)

import data.nat.choose.basic
import data.nat.fib
import data.list.defs
import data.list.nat_antidiagonal

open function

lemma list.sum_map_add {ι α : Type*} [add_comm_monoid α] {f g : ι → α} (l : list ι) :
  (l.map (λ x, f x + g x)).sum = (l.map f).sum + (l.map g).sum  :=
list.sum_hom₂ _ _ add_add_add_comm (add_zero _) _ _

lemma list.nat.antidiagonal_succ' (n : ℕ) :
  list.nat.antidiagonal (n + 1) =
  ((list.nat.antidiagonal n).map (prod.map id nat.succ)) ++ [(n + 1, 0)] :=
begin
  simp only [list.nat.antidiagonal, list.range_succ, add_tsub_cancel_left, list.map_append,
    list.append_assoc, tsub_self, list.singleton_append, list.map_map, list.map],
  congr' 1,
  apply list.map_congr,
  simp [le_of_lt, nat.succ_eq_add_one, nat.sub_add_comm] { contextual := tt },
end

lemma list.nat.antidiagonal_succ_succ' (n : ℕ) :
  list.nat.antidiagonal (n + 2) =
  (0, n + 2) :: ((list.nat.antidiagonal n).map (prod.map nat.succ nat.succ)) ++ [(n + 2, 0)] :=
begin
  induction n with n ih,
  { refl, },
  { rw [nat.succ_add, list.nat.antidiagonal_succ, ih],
    simpa, },
end

theorem fib_eq_sum_choose_antidiagonal (n : ℕ) :
  (n + 1).fib = ((list.nat.antidiagonal n).map (uncurry nat.choose)).sum :=
begin
  induction n using nat.two_step_induction with n h0 h1,
  { refl, },
  { refl, },
  rw [nat.fib_add_two, h0, h1, list.nat.antidiagonal_succ_succ', list.nat.antidiagonal_succ'],
  simpa [←add_assoc, ←list.sum_map_add, uncurry, ←nat.choose_succ_succ],
end
```
 
import data.nat.choose.basic
import data.nat.fib
import data.list.defs
import data.list.nat_antidiagonal

open function

lemma list.sum_map_add {ι α : Type*} [add_comm_monoid α] {f g : ι → α} (l : list ι) :
  (l.map (λ x, f x + g x)).sum = (l.map f).sum + (l.map g).sum  :=
list.sum_hom₂ _ _ add_add_add_comm (add_zero _) _ _

lemma list.nat.antidiagonal_succ' (n : ℕ) :
  list.nat.antidiagonal (n + 1) =
  ((list.nat.antidiagonal n).map (prod.map id nat.succ)) ++ [(n + 1, 0)] :=
begin
  simp only [list.nat.antidiagonal, list.range_succ, add_tsub_cancel_left, list.map_append,
    list.append_assoc, tsub_self, list.singleton_append, list.map_map, list.map],
  congr' 1,
  apply list.map_congr,
  simp [le_of_lt, nat.succ_eq_add_one, nat.sub_add_comm] { contextual := tt },
end

lemma list.nat.antidiagonal_succ_succ' (n : ℕ) :
  list.nat.antidiagonal (n + 2) =
  (0, n + 2) :: ((list.nat.antidiagonal n).map (prod.map nat.succ nat.succ)) ++ [(n + 2, 0)] :=
begin
  induction n with n ih,
  { refl, },
  { rw [nat.succ_add, list.nat.antidiagonal_succ, ih],
    simpa, },
end

theorem fib_eq_sum_choose_antidiagonal (n : ℕ) :
  (n + 1).fib = ((list.nat.antidiagonal n).map (uncurry nat.choose)).sum :=
begin
  induction n using nat.two_step_induction with n h0 h1,
  { refl, },
  { refl, },
  rw [nat.fib_add_two, h0, h1, list.nat.antidiagonal_succ_succ', list.nat.antidiagonal_succ'],
  simpa [←add_assoc, ←list.sum_map_add, uncurry, ←nat.choose_succ_succ],
end

All that said, using lists isn't the usual way you work with sums in mathlib. Instead, you work with finset and the "big operators." Contingent on the mathlib PR for manipulating antidiagonals, the theorem ends up being just this:

import data.finset.nat_antidiagonal
import data.nat.fib
import algebra.big_operators.basic

open_locale big_operators
open finset

theorem fib_eq_sum_choose_antidiagonal (n : ℕ) :
  (n + 1).fib = ∑ p in nat.antidiagonal n, nat.choose p.1 p.2 :=
begin
  induction n using nat.two_step_induction with n h0 h1,
  { refl, },
  { refl, },
  rw [nat.fib_add_two, h0, h1, nat.antidiagonal_succ_succ', nat.antidiagonal_succ'],
  simp [nat.choose_succ_succ, add_assoc, add_left_comm, sum_add_distrib],
end

After doing the basic manipulations you described in your proof outline, simp ends up doing the heavy lifting. An interesting thing about this tactic is that it's able to put things into a normal form even if the lemmas can potentially form rewrite loops. The add_assoc and add_left_comm lemmas here are giving simp the capability of sorting the additions, as a weak kind of ring. (Usually you'd include add_comm, too, but it wasn't necessary here.)

added 80 characters in body
Source Link
Kyle Miller
  • 541
  • 3
  • 10

In these, I'm (somewhat) misusing a feature of simpa, which is that it basically tries refl at the end. (These lemmas should also probably find their way into mathlib, but I'm not too familiar with the list antidiagonal functions. Edit: mathlib#12028 and mathlib#12029 mathlib#12028)

In these, I'm (somewhat) misusing a feature of simpa, which is that it basically tries refl at the end. (These lemmas should also probably find their way into mathlib, but I'm not too familiar with the list antidiagonal functions. Edit: mathlib#12028)

In these, I'm (somewhat) misusing a feature of simpa, which is that it basically tries refl at the end. (These lemmas should also probably find their way into mathlib, but I'm not too familiar with the list antidiagonal functions. Edit: mathlib#12028 and mathlib#12029)

added 84 characters in body
Source Link
Kyle Miller
  • 541
  • 3
  • 10

In these, I'm (somewhat) misusing a feature of simpa, which is that it basically tries refl at the end. (These lemmas should also probably find their way into mathlib, but I'm not too familiar with the list antidiagonal functions. Edit: mathlib#12028)

In these, I'm (somewhat) misusing a feature of simpa, which is that it basically tries refl at the end. (These lemmas should also probably find their way into mathlib, but I'm not too familiar with the list antidiagonal functions.)

In these, I'm (somewhat) misusing a feature of simpa, which is that it basically tries refl at the end. (These lemmas should also probably find their way into mathlib, but I'm not too familiar with the list antidiagonal functions. Edit: mathlib#12028)

removed a non-terminal simp in my own code
Source Link
Kyle Miller
  • 541
  • 3
  • 10
Loading
added 148 characters in body
Source Link
Kyle Miller
  • 541
  • 3
  • 10
Loading
Source Link
Kyle Miller
  • 541
  • 3
  • 10
Loading