|
| 1 | +/- |
| 2 | +Copyright (c) 2019 Johan Commelin. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Johan Commelin |
| 5 | +
|
| 6 | +! This file was ported from Lean 3 source module data.finset.nat_antidiagonal |
| 7 | +! leanprover-community/mathlib commit 9003f28797c0664a49e4179487267c494477d853 |
| 8 | +! Please do not edit these lines, except to modify the commit id |
| 9 | +! if you have ported upstream changes. |
| 10 | +-/ |
| 11 | +import Mathlib.Data.Finset.Card |
| 12 | +import Mathlib.Data.Multiset.NatAntidiagonal |
| 13 | + |
| 14 | +/-! |
| 15 | +# Antidiagonals in ℕ × ℕ as finsets |
| 16 | +
|
| 17 | +This file defines the antidiagonals of ℕ × ℕ as finsets: the `n`-th antidiagonal is the finset of |
| 18 | +pairs `(i, j)` such that `i + j = n`. This is useful for polynomial multiplication and more |
| 19 | +generally for sums going from `0` to `n`. |
| 20 | +
|
| 21 | +## Notes |
| 22 | +
|
| 23 | +This refines files `Data.List.NatAntidiagonal` and `Data.Multiset.NatAntidiagonal`. |
| 24 | +-/ |
| 25 | + |
| 26 | + |
| 27 | +namespace Finset |
| 28 | + |
| 29 | +namespace Nat |
| 30 | + |
| 31 | +/-- The antidiagonal of a natural number `n` is |
| 32 | + the finset of pairs `(i, j)` such that `i + j = n`. -/ |
| 33 | +def antidiagonal (n : ℕ) : Finset (ℕ × ℕ) := |
| 34 | + ⟨Multiset.Nat.antidiagonal n, Multiset.Nat.nodup_antidiagonal n⟩ |
| 35 | +#align finset.nat.antidiagonal Finset.Nat.antidiagonal |
| 36 | + |
| 37 | +/-- A pair (i, j) is contained in the antidiagonal of `n` if and only if `i + j = n`. -/ |
| 38 | +@[simp] |
| 39 | +theorem mem_antidiagonal {n : ℕ} {x : ℕ × ℕ} : x ∈ antidiagonal n ↔ x.1 + x.2 = n := by |
| 40 | + rw [antidiagonal, mem_def, Multiset.Nat.mem_antidiagonal] |
| 41 | +#align finset.nat.mem_antidiagonal Finset.Nat.mem_antidiagonal |
| 42 | + |
| 43 | +/-- The cardinality of the antidiagonal of `n` is `n + 1`. -/ |
| 44 | +@[simp] |
| 45 | +theorem card_antidiagonal (n : ℕ) : (antidiagonal n).card = n + 1 := by simp [antidiagonal] |
| 46 | +#align finset.nat.card_antidiagonal Finset.Nat.card_antidiagonal |
| 47 | + |
| 48 | +/-- The antidiagonal of `0` is the list `[(0, 0)]` -/ |
| 49 | +@[simp] |
| 50 | +theorem antidiagonal_zero : antidiagonal 0 = {(0, 0)} := rfl |
| 51 | +#align finset.nat.antidiagonal_zero Finset.Nat.antidiagonal_zero |
| 52 | + |
| 53 | +theorem antidiagonal_succ (n : ℕ) : |
| 54 | + antidiagonal (n + 1) = |
| 55 | + cons (0, n + 1) |
| 56 | + ((antidiagonal n).map |
| 57 | + (Function.Embedding.prodMap ⟨Nat.succ, Nat.succ_injective⟩ (Function.Embedding.refl _))) |
| 58 | + (by simp) := by |
| 59 | + apply eq_of_veq |
| 60 | + rw [cons_val, map_val] |
| 61 | + · apply Multiset.Nat.antidiagonal_succ |
| 62 | +#align finset.nat.antidiagonal_succ Finset.Nat.antidiagonal_succ |
| 63 | + |
| 64 | +theorem antidiagonal_succ' (n : ℕ) : |
| 65 | + antidiagonal (n + 1) = |
| 66 | + cons (n + 1, 0) |
| 67 | + ((antidiagonal n).map |
| 68 | + (Function.Embedding.prodMap (Function.Embedding.refl _) ⟨Nat.succ, Nat.succ_injective⟩)) |
| 69 | + (by simp) := by |
| 70 | + apply eq_of_veq |
| 71 | + rw [cons_val, map_val] |
| 72 | + exact Multiset.Nat.antidiagonal_succ' |
| 73 | +#align finset.nat.antidiagonal_succ' Finset.Nat.antidiagonal_succ' |
| 74 | + |
| 75 | +theorem antidiagonal_succ_succ' {n : ℕ} : |
| 76 | + antidiagonal (n + 2) = |
| 77 | + cons (0, n + 2) |
| 78 | + (cons (n + 2, 0) |
| 79 | + ((antidiagonal n).map |
| 80 | + (Function.Embedding.prodMap ⟨Nat.succ, Nat.succ_injective⟩ |
| 81 | + ⟨Nat.succ, Nat.succ_injective⟩)) <| |
| 82 | + by simp) |
| 83 | + (by simp) := by |
| 84 | + simp_rw [antidiagonal_succ (n + 1), antidiagonal_succ', Finset.map_cons, map_map] |
| 85 | + rfl |
| 86 | +#align finset.nat.antidiagonal_succ_succ' Finset.Nat.antidiagonal_succ_succ' |
| 87 | + |
| 88 | +theorem map_swap_antidiagonal {n : ℕ} : |
| 89 | + (antidiagonal n).map ⟨Prod.swap, Prod.swap_injective⟩ = antidiagonal n := |
| 90 | + eq_of_veq <| by simp [antidiagonal, Multiset.Nat.map_swap_antidiagonal] |
| 91 | +#align finset.nat.map_swap_antidiagonal Finset.Nat.map_swap_antidiagonal |
| 92 | + |
| 93 | +/-- A point in the antidiagonal is determined by its first co-ordinate. -/ |
| 94 | +theorem antidiagonal_congr {n : ℕ} {p q : ℕ × ℕ} (hp : p ∈ antidiagonal n) |
| 95 | + (hq : q ∈ antidiagonal n) : p = q ↔ p.fst = q.fst := by |
| 96 | + refine' ⟨congr_arg Prod.fst, fun h ↦ Prod.ext h ((add_right_inj q.fst).mp _)⟩ |
| 97 | + rw [mem_antidiagonal] at hp hq |
| 98 | + rw [hq, ← h, hp] |
| 99 | +#align finset.nat.antidiagonal_congr Finset.Nat.antidiagonal_congr |
| 100 | + |
| 101 | +theorem antidiagonal.fst_le {n : ℕ} {kl : ℕ × ℕ} (hlk : kl ∈ antidiagonal n) : kl.1 ≤ n := by |
| 102 | + rw [le_iff_exists_add] |
| 103 | + use kl.2 |
| 104 | + rwa [mem_antidiagonal, eq_comm] at hlk |
| 105 | +#align finset.nat.antidiagonal.fst_le Finset.Nat.antidiagonal.fst_le |
| 106 | + |
| 107 | +theorem antidiagonal.snd_le {n : ℕ} {kl : ℕ × ℕ} (hlk : kl ∈ antidiagonal n) : kl.2 ≤ n := by |
| 108 | + rw [le_iff_exists_add] |
| 109 | + use kl.1 |
| 110 | + rwa [mem_antidiagonal, eq_comm, add_comm] at hlk |
| 111 | +#align finset.nat.antidiagonal.snd_le Finset.Nat.antidiagonal.snd_le |
| 112 | + |
| 113 | +theorem filter_fst_eq_antidiagonal (n m : ℕ) : |
| 114 | + filter (fun x : ℕ × ℕ ↦ x.fst = m) (antidiagonal n) = if m ≤ n then {(m, n - m)} else ∅ := by |
| 115 | + ext ⟨x, y⟩ |
| 116 | + simp only [mem_filter, Nat.mem_antidiagonal] |
| 117 | + split_ifs with h |
| 118 | + · simp (config := { contextual := true }) [and_comm, eq_tsub_iff_add_eq_of_le h, add_comm] |
| 119 | + · rw [not_le] at h |
| 120 | + simp only [not_mem_empty, iff_false_iff, not_and, decide_eq_true_eq] |
| 121 | + exact fun hn => ne_of_lt (lt_of_le_of_lt (le_self_add.trans hn.le) h) |
| 122 | +#align finset.nat.filter_fst_eq_antidiagonal Finset.Nat.filter_fst_eq_antidiagonal |
| 123 | + |
| 124 | +theorem filter_snd_eq_antidiagonal (n m : ℕ) : |
| 125 | + filter (fun x : ℕ × ℕ ↦ x.snd = m) (antidiagonal n) = if m ≤ n then {(n - m, m)} else ∅ := by |
| 126 | + have : (fun x : ℕ × ℕ ↦ (x.snd = m : Bool)) ∘ Prod.swap = fun x : ℕ × ℕ ↦ x.fst = m := by |
| 127 | + ext ; simp |
| 128 | + rw [← map_swap_antidiagonal] |
| 129 | + simp [filter_map, this, filter_fst_eq_antidiagonal, apply_ite (Finset.map _)] |
| 130 | +#align finset.nat.filter_snd_eq_antidiagonal Finset.Nat.filter_snd_eq_antidiagonal |
| 131 | + |
| 132 | +section EquivProd |
| 133 | + |
| 134 | +/-- The disjoint union of antidiagonals `Σ (n : ℕ), antidiagonal n` is equivalent to the product |
| 135 | + `ℕ × ℕ`. This is such an equivalence, obtained by mapping `(n, (k, l))` to `(k, l)`. -/ |
| 136 | +@[simps] |
| 137 | +def sigmaAntidiagonalEquivProd : (Σn : ℕ, antidiagonal n) ≃ ℕ × ℕ where |
| 138 | + toFun x := x.2 |
| 139 | + invFun x := ⟨x.1 + x.2, x, mem_antidiagonal.mpr rfl⟩ |
| 140 | + left_inv := by |
| 141 | + rintro ⟨n, ⟨k, l⟩, h⟩ |
| 142 | + rw [mem_antidiagonal] at h |
| 143 | + exact Sigma.subtype_ext h rfl |
| 144 | + right_inv x := rfl |
| 145 | +#align finset.nat.sigma_antidiagonal_equiv_prod Finset.Nat.sigmaAntidiagonalEquivProd |
| 146 | + |
| 147 | +end EquivProd |
| 148 | + |
| 149 | +end Nat |
| 150 | + |
| 151 | +end Finset |
0 commit comments