|
| 1 | +/- |
| 2 | +Copyright (c) 2024 Jeremy Tan. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Jeremy Tan |
| 5 | +-/ |
| 6 | +import Mathlib.Data.Int.Interval |
| 7 | +import Mathlib.Data.Int.ModEq |
| 8 | +import Mathlib.Data.Nat.Count |
| 9 | +import Mathlib.Data.Nat.Interval |
| 10 | +import Mathlib.Data.Rat.Floor |
| 11 | + |
| 12 | +/-! |
| 13 | +# Counting elements in an interval with given residue |
| 14 | +
|
| 15 | +The theorems in this file generalise `Nat.card_multiples` in `Data.Nat.Factorization.Basic` to |
| 16 | +all integer intervals and any fixed residue (not just zero, which reduces to the multiples). |
| 17 | +Theorems are given for `Ico` and `Ioc` intervals. |
| 18 | +-/ |
| 19 | + |
| 20 | + |
| 21 | +open Finset Int |
| 22 | + |
| 23 | +namespace Int |
| 24 | + |
| 25 | +variable (a b : ℤ) {r : ℤ} (hr : 0 < r) |
| 26 | + |
| 27 | +lemma Ico_filter_dvd_eq : (Ico a b).filter (r ∣ ·) = |
| 28 | + (Ico ⌈a / (r : ℚ)⌉ ⌈b / (r : ℚ)⌉).map ⟨(· * r), mul_left_injective₀ hr.ne'⟩ := by |
| 29 | + ext x |
| 30 | + simp only [mem_map, mem_filter, mem_Ico, ceil_le, lt_ceil, div_le_iff, lt_div_iff, |
| 31 | + dvd_iff_exists_eq_mul_left, cast_pos.2 hr, ← cast_mul, cast_lt, cast_le] |
| 32 | + aesop |
| 33 | + |
| 34 | +lemma Ioc_filter_dvd_eq : (Ioc a b).filter (r ∣ ·) = |
| 35 | + (Ioc ⌊a / (r : ℚ)⌋ ⌊b / (r : ℚ)⌋).map ⟨(· * r), mul_left_injective₀ hr.ne'⟩ := by |
| 36 | + ext x |
| 37 | + simp only [mem_map, mem_filter, mem_Ioc, floor_lt, le_floor, div_lt_iff, le_div_iff, |
| 38 | + dvd_iff_exists_eq_mul_left, cast_pos.2 hr, ← cast_mul, cast_lt, cast_le] |
| 39 | + aesop |
| 40 | + |
| 41 | +/-- There are `⌈b / r⌉ - ⌈a / r⌉` multiples of `r` in `[a, b)`, if `a ≤ b`. -/ |
| 42 | +theorem Ico_filter_dvd_card : ((Ico a b).filter (r ∣ ·)).card = |
| 43 | + max (⌈b / (r : ℚ)⌉ - ⌈a / (r : ℚ)⌉) 0 := by |
| 44 | + rw [Ico_filter_dvd_eq _ _ hr, card_map, card_Ico, toNat_eq_max] |
| 45 | + |
| 46 | +/-- There are `⌊b / r⌋ - ⌊a / r⌋` multiples of `r` in `(a, b]`, if `a ≤ b`. -/ |
| 47 | +theorem Ioc_filter_dvd_card : ((Ioc a b).filter (r ∣ ·)).card = |
| 48 | + max (⌊b / (r : ℚ)⌋ - ⌊a / (r : ℚ)⌋) 0 := by |
| 49 | + rw [Ioc_filter_dvd_eq _ _ hr, card_map, card_Ioc, toNat_eq_max] |
| 50 | + |
| 51 | +lemma Ico_filter_modEq_eq (v : ℤ) : (Ico a b).filter (· ≡ v [ZMOD r]) = |
| 52 | + ((Ico (a - v) (b - v)).filter (r ∣ ·)).map ⟨(· + v), add_left_injective v⟩ := by |
| 53 | + ext x |
| 54 | + simp_rw [mem_map, mem_filter, mem_Ico, Function.Embedding.coeFn_mk, ← eq_sub_iff_add_eq, |
| 55 | + exists_eq_right, modEq_comm, modEq_iff_dvd, sub_lt_sub_iff_right, sub_le_sub_iff_right] |
| 56 | + |
| 57 | +lemma Ioc_filter_modEq_eq (v : ℤ) : (Ioc a b).filter (· ≡ v [ZMOD r]) = |
| 58 | + ((Ioc (a - v) (b - v)).filter (r ∣ ·)).map ⟨(· + v), add_left_injective v⟩ := by |
| 59 | + ext x |
| 60 | + simp_rw [mem_map, mem_filter, mem_Ioc, Function.Embedding.coeFn_mk, ← eq_sub_iff_add_eq, |
| 61 | + exists_eq_right, modEq_comm, modEq_iff_dvd, sub_lt_sub_iff_right, sub_le_sub_iff_right] |
| 62 | + |
| 63 | +/-- There are `⌈(b - v) / r⌉ - ⌈(a - v) / r⌉` numbers congruent to `v` mod `r` in `[a, b)`, |
| 64 | +if `a ≤ b`. -/ |
| 65 | +theorem Ico_filter_modEq_card (v : ℤ) : ((Ico a b).filter (· ≡ v [ZMOD r])).card = |
| 66 | + max (⌈(b - v) / (r : ℚ)⌉ - ⌈(a - v) / (r : ℚ)⌉) 0 := by |
| 67 | + simp [Ico_filter_modEq_eq, Ico_filter_dvd_eq, toNat_eq_max, hr] |
| 68 | + |
| 69 | +/-- There are `⌊(b - v) / r⌋ - ⌊(a - v) / r⌋` numbers congruent to `v` mod `r` in `(a, b]`, |
| 70 | +if `a ≤ b`. -/ |
| 71 | +theorem Ioc_filter_modEq_card (v : ℤ) : ((Ioc a b).filter (· ≡ v [ZMOD r])).card = |
| 72 | + max (⌊(b - v) / (r : ℚ)⌋ - ⌊(a - v) / (r : ℚ)⌋) 0 := by |
| 73 | + simp [Ioc_filter_modEq_eq, Ioc_filter_dvd_eq, toNat_eq_max, hr] |
| 74 | + |
| 75 | +end Int |
| 76 | + |
| 77 | +namespace Nat |
| 78 | + |
| 79 | +variable (a b : ℕ) {r : ℕ} (hr : 0 < r) |
| 80 | + |
| 81 | +lemma Ico_filter_modEq_cast {v : ℕ} : ((Ico a b).filter (· ≡ v [MOD r])).map castEmbedding = |
| 82 | + (Ico ↑a ↑b).filter (· ≡ v [ZMOD r]) := by |
| 83 | + ext x |
| 84 | + simp only [mem_map, mem_filter, mem_Ico, castEmbedding_apply] |
| 85 | + constructor |
| 86 | + · simp_rw [forall_exists_index, ← coe_nat_modEq_iff]; intro y ⟨h, c⟩; subst c; exact_mod_cast h |
| 87 | + · intro h; lift x to ℕ using (by linarith); exact ⟨x, by simp_all [coe_nat_modEq_iff]⟩ |
| 88 | + |
| 89 | +lemma Ioc_filter_modEq_cast {v : ℕ} : ((Ioc a b).filter (· ≡ v [MOD r])).map castEmbedding = |
| 90 | + (Ioc ↑a ↑b).filter (· ≡ v [ZMOD r]) := by |
| 91 | + ext x |
| 92 | + simp only [mem_map, mem_filter, mem_Ioc, castEmbedding_apply] |
| 93 | + constructor |
| 94 | + · simp_rw [forall_exists_index, ← coe_nat_modEq_iff]; intro y ⟨h, c⟩; subst c; exact_mod_cast h |
| 95 | + · intro h; lift x to ℕ using (by linarith); exact ⟨x, by simp_all [coe_nat_modEq_iff]⟩ |
| 96 | + |
| 97 | +/-- There are `⌈(b - v) / r⌉ - ⌈(a - v) / r⌉` numbers congruent to `v` mod `r` in `[a, b)`, |
| 98 | +if `a ≤ b`. `Nat` version of `Int.Ico_filter_modEq_card`. -/ |
| 99 | +theorem Ico_filter_modEq_card (v : ℕ) : ((Ico a b).filter (· ≡ v [MOD r])).card = |
| 100 | + max (⌈(b - v) / (r : ℚ)⌉ - ⌈(a - v) / (r : ℚ)⌉) 0 := by |
| 101 | + simp_rw [← Ico_filter_modEq_cast _ _ ▸ card_map _, |
| 102 | + Int.Ico_filter_modEq_card _ _ (cast_lt.mpr hr), Int.cast_ofNat] |
| 103 | + |
| 104 | +/-- There are `⌊(b - v) / r⌋ - ⌊(a - v) / r⌋` numbers congruent to `v` mod `r` in `(a, b]`, |
| 105 | +if `a ≤ b`. `Nat` version of `Int.Ioc_filter_modEq_card`. -/ |
| 106 | +theorem Ioc_filter_modEq_card (v : ℕ) : ((Ioc a b).filter (· ≡ v [MOD r])).card = |
| 107 | + max (⌊(b - v) / (r : ℚ)⌋ - ⌊(a - v) / (r : ℚ)⌋) 0 := by |
| 108 | + simp_rw [← Ioc_filter_modEq_cast _ _ ▸ card_map _, |
| 109 | + Int.Ioc_filter_modEq_card _ _ (cast_lt.mpr hr), Int.cast_ofNat] |
| 110 | + |
| 111 | +/-- There are `⌈(b - v % r) / r⌉` numbers in `[0, b)` congruent to `v` mod `r`. -/ |
| 112 | +theorem count_modEq_card_eq_ceil (v : ℕ) : |
| 113 | + b.count (· ≡ v [MOD r]) = ⌈(b - (v % r : ℕ)) / (r : ℚ)⌉ := by |
| 114 | + have hr' : 0 < (r : ℚ) := by positivity |
| 115 | + rw [count_eq_card_filter_range, ← Ico_zero_eq_range, Ico_filter_modEq_card _ _ hr, |
| 116 | + max_eq_left (sub_nonneg.mpr <| by gcongr <;> positivity)] |
| 117 | + conv_lhs => |
| 118 | + rw [← div_add_mod v r, cast_add, cast_mul, add_comm] |
| 119 | + tactic => simp_rw [← sub_sub, sub_div (_ - _), mul_div_cancel_left _ hr'.ne', ceil_sub_nat] |
| 120 | + rw [sub_sub_sub_cancel_right, cast_zero, zero_sub] |
| 121 | + rw [sub_eq_self, ceil_eq_zero_iff, Set.mem_Ioc, div_le_iff hr', lt_div_iff hr', neg_one_mul, |
| 122 | + zero_mul, neg_lt_neg_iff, cast_lt] |
| 123 | + exact ⟨mod_lt _ hr, by simp⟩ |
| 124 | + |
| 125 | +/-- There are `b / r + [v % r < b % r]` numbers in `[0, b)` congruent to `v` mod `r`, |
| 126 | +where `[·]` is the Iverson bracket. -/ |
| 127 | +theorem count_modEq_card (v : ℕ) : |
| 128 | + b.count (· ≡ v [MOD r]) = b / r + if v % r < b % r then 1 else 0 := by |
| 129 | + have hr' : 0 < (r : ℚ) := by positivity |
| 130 | + rw [← ofNat_inj, count_modEq_card_eq_ceil _ hr, cast_add] |
| 131 | + conv_lhs => rw [← div_add_mod b r, cast_add, cast_mul, ← add_sub, _root_.add_div, |
| 132 | + mul_div_cancel_left _ hr'.ne', add_comm, Int.ceil_add_nat, add_comm] |
| 133 | + rw [add_right_inj] |
| 134 | + split_ifs with h |
| 135 | + · rw [← cast_sub h.le, Int.ceil_eq_iff, div_le_iff hr', lt_div_iff hr', cast_one, Int.cast_one, |
| 136 | + sub_self, zero_mul, cast_pos, tsub_pos_iff_lt, one_mul, cast_le, tsub_le_iff_right] |
| 137 | + exact ⟨h, ((mod_lt _ hr).trans_le (by simp)).le⟩ |
| 138 | + · rw [cast_zero, ceil_eq_zero_iff, Set.mem_Ioc, div_le_iff hr', lt_div_iff hr', zero_mul, |
| 139 | + tsub_nonpos, ← neg_eq_neg_one_mul, neg_lt_sub_iff_lt_add, ← cast_add, cast_lt, cast_le] |
| 140 | + exact ⟨(mod_lt _ hr).trans_le (by simp), not_lt.mp h⟩ |
| 141 | + |
| 142 | +end Nat |
0 commit comments