Maxima で綴る数学の旅

紙と鉛筆の代わりに、数式処理システムMaxima / Macsyma を使って、数学を楽しみましょう

-Lean4のお勉強 3の倍数の確認法(任意桁版)

有限の場合の総和記号について勉強したことで任意桁数の場合の3の倍数の確認方法について形式化して証明することが出来そうです。ということでやってみました。

 

まず与えられた自然数が3の倍数かどうかの確認方法と普通の証明をざっと述べてみます。

3の倍数の確認方法:$N, i, a_i$を自然数として$a_i$は各桁の数を表します。従って$\sum_{i=0}^{N-1} a_i\cdot 10^i$が与えられた自然数です。確認方法は、
$$3 | \sum_{i=0}^{N-1} a_i\cdot 10^i \iff 3 | \sum_{i=0}^{N-1} a_i$$
が成り立つので、右辺の和(各桁の数の和)を計算して3の倍数かどうかみれば与えられた自然数(左辺の和)が3の倍数かどうかわかります。というわけで上記の式を証明します。

 

証明:
前の記事で紹介した定理divisable_add:$a,b,k$を自然数として$k|a$ならば$k|(a+b)$と$k|b$は同値。
を最後のステップで使いたいのです。そこで目標として

$$\tag{A}\sum_{i=0}^{N-1} a_i\cdot 10^i=\sum_{i=0}^{N-1} a_i\cdot (10^i-1) + \sum_{i=0}^{N-1} a_i$$及び$$\tag{B}3| \sum_{i=0}^{N-1} a_i\cdot (10^i-1) $$を示すことにします。

(A)は総和の和は和の総和、ということで有限の総和では自明です。

(B)は$3 | 10^k - 1$であることを示し、さらに一般的に$ \forall i\in \mathbb{N}及び0\le m\in\mathbb{N}, m|f(i) \implies m| \sum_{i=0}^{N-1} a_i\cdot f(i)$を示すことで示すことができます。

 

上記の流れを形式化したものを示します。

example {N:ℕ} :  3∣ (∑ i in range N, (a i)*10^i) ↔ 3∣ (∑ i in range N, (a i)) := by
  have h0 {k:ℕ} : 3∣ 10^k-1 := by sorry
  have h5 {i:ℕ}: (a i)*(10^i-1)+(a i)=(a i)*10^i := by sorry
  have h6: ∑ i in range N, (a i)*10^i=∑ i in range N, ( (a i)*(10^i-1)+(a i)) := by sorry
  have h7: ∑ i in range N, ( (a i)*(10^i-1)+(a i))=(∑ i in range N, (a i)*(10^i-1)) + ∑ i in range N, (a i) := by sorry
  have h8: 3∣ ∑ i in range N, (a i)*(10^i-1) := by sorry
  rw [h6,h7]
  apply divisable_add h8

ただし補題h0〜h8の証明は一旦sorryとして流れだけ見えるようにしてあります。h5, h6, h7で(A)を示しています。またh0, h8で(B)を示しています。最後の2行で総和の式変形とdivisable_addによる同値条件から証明が終了します。

 

以下に形式証明を全部載せるのですが、全部で100行近くになってしまいました。特に解説は載せませんので、ご自身の環境で試していただければと思います。

上記のh0〜h8で一番行数がかかっているのはh0です。特に$10^{k+1}-1=10\cdot (10^k - 1)+9$という式変形で10行もかかっていていかにも下手くそな感じです,,, orz

import Mathlib.Data.Nat.GCD.Basic
import Mathlib.Algebra.BigOperators.Basic
import Mathlib.Data.Nat.Factorization.Basic

open BigOperators
open Finset
variable (a : ℕ → ℕ ) (f : ℕ → ℕ )


theorem divisable_add {a b k:ℕ } (h: k∣a) : k∣(a+b)↔k∣b := by
  rcases h with ⟨m,hh⟩
  constructor
  · intro h1
    rcases h1 with ⟨ n, h2⟩
    rw [hh] at h2
    have h3: b= k*n-k*m := by exact (tsub_eq_of_eq_add_rev (id h2.symm)).symm
    have : b = k*(n-m) := by
      rw [← Nat.mul_sub_left_distrib k n m] at h3; assumption
    rw [this]
    exact Nat.dvd_mul_right k (n - m)
  intro h1
  rcases h1 with ⟨ n,h2⟩
  rw [hh,h2]
  have : k*m+k*n=k*(m+n) := by exact (Nat.mul_add k m n).symm
  rw [this]
  exact Nat.dvd_mul_right k (m + n)


theorem divisable_add' {a b k: ℕ} : k∣ a → (k∣b ↔ k∣ (a+b)) := by
  intro h'
  symm
  apply divisable_add h'

 

theorem sum_term_divisable {f:ℕ→ℕ} {d N:ℕ}: (∀ j:ℕ, d∣(f j)) → d∣∑ i in range N, (a i)*(f i) := by
  intro h1
  induction' N with k ih
  · exact Nat.dvd_of_mod_eq_zero rfl

  have h2: d∣ (a k)*(f k) := by exact Dvd.dvd.mul_left (h1 k) (a k)
  have h3: d∣ (a k)*(f k)+∑ i in range k, (a i)*(f i) ↔ d∣ ∑ i in range k, (a i)*(f i) := by
    apply divisable_add h2
  have h4: (a k)*(f k)+∑ i in range k, (a i)*(f i)=∑ i in range (Nat.succ k), (a i)*(f i) := by exact
    (sum_range_succ_comm (fun x ↦ a x * f x) k).symm
  rw [← h4,h3]
  assumption

 

example {N:ℕ} :  3∣ (∑ i in range N, (a i)*10^i) ↔ 3∣ (∑ i in range N, (a i)) := by
  have h0 {k:ℕ} : 3∣ 10^k-1 := by
    induction' k with k ih
    · simp
    have h1: 10^(k+1)-1=10*(10^k-1)+9 := by
      have h9: 9≤9 := by linarith
      have asc: 10≤ 10*10^k := by
        have : 1≤ 10^k := by exact Nat.one_le_pow' k 9
        exact Nat.le_mul_of_pos_right 10 this
      calc
        10^(k+1)-1 = 10*10^k - 1 := by omega
        _ = 9 - 9 + (10*10^k - 1) := by exact self_eq_add_left.mpr rfl
        _ = 9 + (10*10^k - 1) - 9 := by rw [tsub_add_eq_add_tsub h9]
        _ = 9 + 10*10^k - 1 - 9 := by omega
        _ = 9 + 10*10^k - 10 := by exact rfl
        _ = 9 + (10*10^k - 10) := by refine add_tsub_assoc_of_le asc 9
        _ = 10*(10^k-1)+9 := by omega
    rw [h1,add_comm]
    have h2: 3∣9 := by norm_num
    have h3: 3∣10*(10^k-1) := by omega
    refine (divisable_add' h2).mp h3
  have h5 {i:ℕ}: (a i)*(10^i-1)+(a i)=(a i)*10^i := by
    have h4 {i:ℕ} : (a i)*10^i ≥ (a i) := by
      have : 1≤ 10^i := by exact Nat.one_le_pow' i 9
      exact Nat.le_mul_of_pos_right (a i) this
    calc
      (a i)*(10^i-1)+(a i)=(a i)*10^i - (a i) + (a i) := by rw [Nat.mul_sub_left_distrib (a i) (10^i) 1]; simp
      _ = (a i)*10^i := by rw [Nat.sub_add_cancel h4]
  have h6: ∑ i in range N, (a i)*10^i=∑ i in range N, ( (a i)*(10^i-1)+(a i)) := by
    apply Finset.sum_congr
    · rfl
    intro x _
    symm
    apply h5
  have h7: ∑ i in range N, ( (a i)*(10^i-1)+(a i))=(∑ i in range N, (a i)*(10^i-1)) + ∑ i in range N, (a i) := by
    exact sum_add_distrib
  have h8: 3∣ ∑ i in range N, (a i)*(10^i-1) := by
    apply sum_term_divisable
    apply h0
  rw [h6,h7]
  apply divisable_add h8