Last active
February 24, 2026 17:10
-
-
Save mizar/8bdc0cfffba61b6de1eb0acce59fdd39 to your computer and use it in GitHub Desktop.
[Accuracy of Integer Division Approximate Function 2 解説](https://zenn.dev/mizar/articles/79ef8c9680265f) の形式的証明
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Mathlib | |
| import Mwf | |
| namespace Divapprox | |
| /-- | |
| 目的: 整数除算近似の誤差関数 `Δ(D,A,B,x)` を定義する。 | |
| 定義: `Δ = ⌊x/D⌋ - ⌊⌊x/A⌋ * ⌊AB/D⌋ / B⌋` を `Int` の除算で実装する。 | |
| 入力/前提: D A B x : Int、_hD : 0 < D、_hA : 0 < A。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `K < Δ` の判定変形・存在条件・最小解探索の基準になる中心定義。 | |
| -/ | |
| def Delta (D A B x : Int) (_hD : 0 < D) (_hA : 0 < A) (_hB : 0 < B) : Int := | |
| (x / D) - (((x / A) * ((A * B) / D)) / B) | |
| /-- | |
| 目的: `M = ⌊AB/D⌋` を補助記号として定義する。 | |
| 定義: `(A * B) / D` を名前付きで切り出す。 | |
| 入力/前提: D A B : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 判定式 `Bu - M⌊Du/A⌋` や canonical 形を簡潔に書くために使う。 | |
| -/ | |
| def Mof (D A B : Int) : Int := | |
| (A * B) / D | |
| /-- | |
| 目的: `R = (AB) mod D` を補助記号として定義する。 | |
| 定義: `(A * B) % D` を名前付きで切り出す。 | |
| 入力/前提: D A B : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `R = 0` / `R ≠ 0` の存在判定と探索上界の分岐軸になる。 | |
| -/ | |
| def Rof (D A B : Int) : Int := | |
| (A * B) % D | |
| section Criterion | |
| variable {D A B K u M R : Int} | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `x = D*u` を代入した `Delta` を `u` 主体の形へ書き換える。 | |
| 内容: `Δ(D,A,B,Du) = u - ((M * ((D*u)/A)) / B)`(`M = ⌊AB/D⌋`)を示す。 | |
| 証明: 式変形で示す。 | |
| 役割: 以降の不等式変形 `K < Δ` の出発点。 | |
| -/ | |
| lemma Delta_Du_rewrite | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (_hu : 0 ≤ u) | |
| (hM : M = (A * B) / D) : | |
| Delta D A B (D * u) hD hA hB = u - ((M * ((D * u) / A)) / B) := by | |
| have hD0 : D ≠ 0 := ne_of_gt hD | |
| unfold Delta | |
| rw [Int.mul_ediv_cancel_left u hD0, hM] | |
| simp only [mul_comm] | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `K < Δ(D,A,B,Du)` と `B*K < B*u - M*((D*u)/A)` は同値。 | |
| 内容: `Delta_Du_rewrite` で展開後、`q := M*((D*u)/A)` を置いて除算不等式を往復する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `Δ` の比較を `f(u)` 型の一次式判定へ落とす第一段。 | |
| -/ | |
| lemma lt_Delta_iff_BK_lt | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hu : 0 ≤ u) | |
| (_hK : 0 ≤ K) | |
| (hM : M = (A * B) / D) : | |
| K < Delta D A B (D * u) hD hA hB ↔ B * K < B * u - M * ((D * u) / A) := by | |
| rw [Delta_Du_rewrite (D := D) (A := A) (B := B) (u := u) (M := M) hD hA hB hu hM] | |
| let q : Int := M * ((D * u) / A) | |
| constructor | |
| · intro h | |
| have hsum : K + q / B < u := (lt_sub_iff_add_lt).1 h | |
| have hqdiv : q / B < u - K := by | |
| exact (lt_sub_iff_add_lt).2 (by simpa only [add_comm] using hsum) | |
| have hqmul : q < (u - K) * B := (Int.ediv_lt_iff_lt_mul hB).1 hqdiv | |
| have hq' : q < B * u - B * K := by | |
| calc | |
| q < (u - K) * B := hqmul | |
| _ = B * u - B * K := by ring | |
| have hsum' : B * K + q < B * u := by | |
| have : q + B * K < B * u := (lt_sub_iff_add_lt).1 hq' | |
| simpa only [gt_iff_lt, add_comm] using this | |
| have : B * K < B * u - q := (lt_sub_iff_add_lt).2 hsum' | |
| simpa only [gt_iff_lt] using this | |
| · intro h | |
| have hsum : B * K + q < B * u := (lt_sub_iff_add_lt).1 h | |
| have hq' : q < B * u - B * K := by | |
| have : q + B * K < B * u := by | |
| simpa only [add_comm] using hsum | |
| exact (lt_sub_iff_add_lt).2 this | |
| have hqmul : q < (u - K) * B := by | |
| calc | |
| q < B * u - B * K := hq' | |
| _ = (u - K) * B := by ring | |
| have hqdiv : q / B < u - K := (Int.ediv_lt_iff_lt_mul hB).2 hqmul | |
| have hsum' : K + q / B < u := by | |
| have : q / B + K < u := (lt_sub_iff_add_lt).1 hqdiv | |
| simpa only [gt_iff_lt, add_comm] using this | |
| have : K < u - q / B := (lt_sub_iff_add_lt).2 hsum' | |
| simpa only [gt_iff_lt] using this | |
| /-- | |
| 入力/前提: hA : 0 < A、_hB : 0 < B、_hD : 0 < D。 | |
| 主張: `B*K < B*u - M*((D*u)/A)` と `A*B*K < ((D*u)%A)*M + R*u` は同値。 | |
| 内容: `AB = D*M + R` と `D*u = A*q + t`(`q=(D*u)/A`, `t=(D*u)%A`)を用いて代数変形する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 余りと `R*u` を明示した canonical 判定式への変換を担う。 | |
| -/ | |
| lemma BK_lt_iff_ABK_lt | |
| (hA : 0 < A) | |
| (_hB : 0 < B) | |
| (_hD : 0 < D) | |
| (_hu : 0 ≤ u) | |
| (_hK : 0 ≤ K) | |
| (hM : M = (A * B) / D) | |
| (hR : R = (A * B) % D) : | |
| B * K < B * u - M * ((D * u) / A) ↔ | |
| A * B * K < ((D * u) % A) * M + R * u := by | |
| let q : Int := (D * u) / A | |
| let t : Int := (D * u) % A | |
| have hAB' : D * M + R = A * B := by | |
| simpa only [hM, hR] using (Int.mul_ediv_add_emod (A * B) D) | |
| have hAB : A * B = D * M + R := hAB'.symm | |
| have hDu : A * q + t = D * u := by | |
| simpa only using (Int.mul_ediv_add_emod (D * u) A) | |
| have hDu_sub : D * u - A * q = t := by | |
| exact (sub_eq_iff_eq_add).2 (by simpa only [add_comm] using hDu.symm) | |
| have hRight : A * (B * u - M * q) = t * M + R * u := by | |
| calc | |
| A * (B * u - M * q) = A * B * u - A * M * q := by ring | |
| _ = (D * M + R) * u - A * M * q := by rw [hAB] | |
| _ = M * (D * u - A * q) + R * u := by ring | |
| _ = M * t + R * u := by rw [hDu_sub] | |
| _ = t * M + R * u := by ring | |
| constructor | |
| · intro h | |
| have hmul : A * (B * K) < A * (B * u - M * q) := (Int.mul_lt_mul_left hA).2 h | |
| calc | |
| A * B * K = A * (B * K) := by ring | |
| _ < A * (B * u - M * q) := hmul | |
| _ = t * M + R * u := hRight | |
| _ = ((D * u) % A) * M + R * u := by simp only [t] | |
| · intro h | |
| have hmul : A * (B * K) < A * (B * u - M * q) := by | |
| calc | |
| A * (B * K) = A * B * K := by ring | |
| _ < ((D * u) % A) * M + R * u := h | |
| _ = t * M + R * u := by simp only [t] | |
| _ = A * (B * u - M * q) := hRight.symm | |
| exact (Int.mul_lt_mul_left hA).1 hmul | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `K < Δ(D,A,B,Du)` と `A*B*K < ((D*u)%A)*M + R*u` の最終同値を与える。 | |
| 内容: `lt_Delta_iff_BK_lt` と `BK_lt_iff_ABK_lt` を `Iff.trans` で連結する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 可解性証明・上界証明・探索判定の共通インターフェース。 | |
| -/ | |
| theorem lt_Delta_iff_ABK_lt | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hu : 0 ≤ u) | |
| (hK : 0 ≤ K) | |
| (hM : M = (A * B) / D) | |
| (hR : R = (A * B) % D) : | |
| K < Delta D A B (D * u) hD hA hB ↔ | |
| A * B * K < ((D * u) % A) * M + R * u := by | |
| refine | |
| (lt_Delta_iff_BK_lt | |
| (D := D) (A := A) (B := B) (K := K) (u := u) (M := M) | |
| hD hA hB hu hK hM).trans ?_ | |
| exact | |
| BK_lt_iff_ABK_lt | |
| (D := D) (A := A) (B := B) (K := K) (u := u) (M := M) (R := R) | |
| hA hB hD hu hK hM hR | |
| end Criterion | |
| section NonIncAndSearch | |
| variable {D A B K x : Int} | |
| /-- | |
| 目的: `x` 側での最小解仕様を述語として定義する。 | |
| 定義: `x0 ≥ 0`、`K < Δ(x0)`、および任意の可解 `y` に対する `x0 ≤ y` を束ねる。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 最小解が `D` の倍数であること(`dvd_of_IsLeastX`)を形式化する土台。 | |
| -/ | |
| def IsLeastX | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (x0 : Int) : Prop := | |
| 0 ≤ x0 ∧ | |
| K < Delta D A B x0 hD hA hB ∧ | |
| ∀ y : Int, 0 ≤ y → K < Delta D A B y hD hA hB → x0 ≤ y | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `D ∤ (x+1)` なら `Δ(D,A,B,x+1) ≤ Δ(D,A,B,x)`。 | |
| 内容: 第1項 `⌊x/D⌋` の不変性と補正項の単調非減少性を組み合わせて示す。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `Δ` が増える可能性が `D` の倍数境界に限られることを与える。 | |
| -/ | |
| lemma Delta_noninc_of_not_dvd_succ | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (_hx : 0 ≤ x) | |
| (hndvd : ¬ D ∣ (x + 1)) : | |
| Delta D A B (x + 1) hD hA hB ≤ Delta D A B x hD hA hB := by | |
| let q : Int := x / D | |
| let r : Int := x % D | |
| have hD0 : D ≠ 0 := ne_of_gt hD | |
| have hMain : (x + 1) / D = x / D := by | |
| have hxdecomp : x = D * q + r := by | |
| simpa only using (Int.mul_ediv_add_emod x D).symm | |
| have hr0 : 0 ≤ r := Int.emod_nonneg _ hD0 | |
| have hrlt : r < D := Int.emod_lt_of_pos _ hD | |
| have hr1le : r + 1 ≤ D := (Int.add_one_le_iff).2 hrlt | |
| have hr1ne : r + 1 ≠ D := by | |
| intro hr1eq | |
| apply hndvd | |
| refine ⟨q + 1, ?_⟩ | |
| calc | |
| x + 1 = D * q + (r + 1) := by omega | |
| _ = D * q + D := by rw [hr1eq] | |
| _ = D * (q + 1) := by ring | |
| have hr1lt : r + 1 < D := lt_of_le_of_ne hr1le hr1ne | |
| have hr1nonneg : 0 ≤ r + 1 := by omega | |
| have hr1div0 : (r + 1) / D = 0 := Int.ediv_eq_zero_of_lt hr1nonneg hr1lt | |
| have hx1 : x + 1 = r + 1 + q * D := by | |
| calc | |
| x + 1 = (D * q + r) + 1 := by rw [hxdecomp] | |
| _ = r + 1 + q * D := by ring | |
| calc | |
| (x + 1) / D = (r + 1 + q * D) / D := by rw [hx1] | |
| _ = (r + 1) / D + q := Int.add_mul_ediv_right _ _ hD0 | |
| _ = q := by simp only [hr1div0, zero_add] | |
| _ = x / D := by simp only [q] | |
| have hCorr : | |
| ((x / A) * ((A * B) / D)) / B ≤ | |
| (((x + 1) / A) * ((A * B) / D)) / B := by | |
| have hMnonneg : 0 ≤ (A * B) / D := by | |
| exact Int.ediv_nonneg (le_of_lt (Int.mul_pos hA hB)) (le_of_lt hD) | |
| have hAdiv : x / A ≤ (x + 1) / A := Int.ediv_le_ediv hA (by omega) | |
| have hMul : | |
| (x / A) * ((A * B) / D) ≤ | |
| ((x + 1) / A) * ((A * B) / D) := by | |
| exact mul_le_mul_of_nonneg_right hAdiv hMnonneg | |
| exact Int.ediv_le_ediv hB hMul | |
| have hSub : | |
| (x + 1) / D - ((((x + 1) / A) * ((A * B) / D)) / B) ≤ | |
| x / D - (((x / A) * ((A * B) / D)) / B) := by | |
| calc | |
| (x + 1) / D - ((((x + 1) / A) * ((A * B) / D)) / B) | |
| = x / D - ((((x + 1) / A) * ((A * B) / D)) / B) := by rw [hMain] | |
| _ ≤ x / D - (((x / A) * ((A * B) / D)) / B) := sub_le_sub_left hCorr (x / D) | |
| simpa only [Delta, tsub_le_iff_right, ge_iff_le] using hSub | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `K < Δ(D,A,B,x)` を満たす最小の `x` は `D` の倍数。 | |
| 内容: `D ∤ x0` を仮定して `x0-1` に `Delta_noninc_of_not_dvd_succ` を適用し最小性と矛盾させる。 | |
| 証明: 反証法・既存補題の書き換えで示す。 | |
| 役割: 探索変数を `x` から `u`(`x = D*u`)へ落とす正当化。 | |
| -/ | |
| lemma dvd_of_IsLeastX | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| {x0 : Int} | |
| (hmin : IsLeastX D A B K hD hA hB x0) : | |
| D ∣ x0 := by | |
| rcases hmin with ⟨hx0, hKx0, hleast⟩ | |
| by_contra hndvd | |
| have hx0ne0 : x0 ≠ 0 := by | |
| intro hx0eq | |
| apply hndvd | |
| exact hx0eq ▸ dvd_zero D | |
| have hx0pos : 0 < x0 := lt_of_le_of_ne hx0 hx0ne0.symm | |
| have hx0m1 : 0 ≤ x0 - 1 := by omega | |
| have hnoninc : | |
| Delta D A B ((x0 - 1) + 1) hD hA hB ≤ | |
| Delta D A B (x0 - 1) hD hA hB := by | |
| exact Delta_noninc_of_not_dvd_succ | |
| (D := D) (A := A) (B := B) (x := x0 - 1) | |
| hD hA hB hx0m1 (by simpa only [sub_add_cancel] using hndvd) | |
| have hKx0m1 : K < Delta D A B (x0 - 1) hD hA hB := by | |
| have hKx0' : K < Delta D A B ((x0 - 1) + 1) hD hA hB := by | |
| simpa only [sub_add_cancel] using hKx0 | |
| exact lt_of_lt_of_le hKx0' hnoninc | |
| have hle : x0 ≤ x0 - 1 := hleast (x0 - 1) hx0m1 hKx0m1 | |
| omega | |
| /-- | |
| 目的: `x` 側の可解性述語を定義する。 | |
| 定義: `0 ≤ x` かつ `K < Delta D A B x` を満たすことを `SolX` とする。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 最小解存在条件・二分探索仕様の共通前提。 | |
| -/ | |
| def SolX | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (x : Int) : Prop := | |
| 0 ≤ x ∧ K < Delta D A B x hD hA hB | |
| /-- | |
| 目的: `u` 側の可解性述語を定義する。 | |
| 定義: `0 ≤ u` かつ `K < Delta D A B (D*u)` を満たすことを `SolU` とする。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: `uMinOf`・存在条件・二分探索仕様の共通前提。 | |
| -/ | |
| def SolU | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (u : Int) : Prop := | |
| 0 ≤ u ∧ K < Delta D A B (D * u) hD hA hB | |
| /-- | |
| 目的: 可解集合から `x` 側の最小解を定義する。 | |
| 定義: `hex : ∃ x, SolX ... x` の下で `{x | SolX ... x}` の `sInf` を返す。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A、hB : 0 < B、`hex : ∃ x, SolX ... x`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `xMin` と実装正当化定理が一致させる `x` 側の数学的ターゲット。 | |
| -/ | |
| noncomputable def xMinOf | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (_hex : ∃ x : Int, SolX D A B K hD hA hB x) : Int := | |
| by | |
| classical | |
| exact sInf {x : Int | SolX D A B K hD hA hB x} | |
| /-- | |
| 目的: 可解集合から `u` 側の最小解を定義する。 | |
| 定義: `hex : ∃ u, SolU ... u` の下で `{u | SolU ... u}` の `sInf` を返す。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A、hB : 0 < B、`hex : ∃ u, SolU ... u`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `uMin`・探索境界補題・実装正当化定理で参照する `u` 側の数学的ターゲット。 | |
| -/ | |
| noncomputable def uMinOf | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (_hex : ∃ u : Int, SolU D A B K hD hA hB u) : Int := | |
| by | |
| classical | |
| exact sInf {u : Int | SolU D A B K hD hA hB u} | |
| /-- | |
| 目的: 問題で求める最小入力 `xMin` の仕様値を定義する。 | |
| 定義: `∃ x, SolX ... x` が成り立てば `xMinOf`、成り立たなければ `-1` を返す。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 実装 `compute_xMin` が一致すべき最終仕様値を与える。 | |
| -/ | |
| noncomputable def xMin | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) : Int := | |
| by | |
| classical | |
| exact | |
| if hex : ∃ x : Int, SolX D A B K hD hA hB x then | |
| xMinOf D A B K hD hA hB hex | |
| else | |
| -1 | |
| /-- | |
| 目的: `u` 側の最小解出力 `uMin` を定義する。 | |
| 定義: `∃ u, SolU ... u` が成り立てば `uMinOf`、成り立たなければ `-1` を返す。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `xMin` との対応付けや探索境界証明で使う `u` 側仕様値を与える。 | |
| -/ | |
| noncomputable def uMin | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) : Int := | |
| by | |
| classical | |
| exact | |
| if hex : ∃ u : Int, SolU D A B K hD hA hB u then | |
| uMinOf D A B K hD hA hB hex | |
| else | |
| -1 | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `u` 側に解があるとき `xMin = D * uMinOf`。 | |
| 内容: `hex` から `SolX` の解を構成し、`xMinOf` を最小解 `x0` とおく。 | |
| `dvd_of_IsLeastX` で `x0 = D*u0` を得て `u0` が `SolU` を満たすことを示し、 | |
| `uMinOf` の最小性と `x0` の最小性を突き合わせて `u0 = uMinOf` を導く。 | |
| 証明: `csInf_mem`/`csInf_le` による最小元の性質、`dvd_of_IsLeastX`、および | |
| `Int.mul_le_mul_left`(`D>0`)を用いて示す。 | |
| 役割: `u` 側最小解を最終出力 `x` 側へ戻す橋渡し。 | |
| -/ | |
| lemma xMin_eq_D_mul_uMinOf | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : ∃ u : Int, SolU D A B K hD hA hB u) : | |
| xMin D A B K hD hA hB = | |
| D * uMinOf D A B K hD hA hB hex := by | |
| classical | |
| have hexX : ∃ x : Int, SolX D A B K hD hA hB x := by | |
| rcases hex with ⟨u, hu⟩ | |
| exact ⟨D * u, ⟨mul_nonneg (le_of_lt hD) hu.1, hu.2⟩⟩ | |
| have hBddX : BddBelow ({x : Int | SolX D A B K hD hA hB x} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| have hBddU : BddBelow ({u : Int | SolU D A B K hD hA hB u} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| let x0 : Int := xMinOf D A B K hD hA hB hexX | |
| have hx0sol : SolX D A B K hD hA hB x0 := by | |
| dsimp only [x0] | |
| unfold xMinOf | |
| exact Int.csInf_mem (by simpa only using hexX) hBddX | |
| have hx0least : IsLeastX D A B K hD hA hB x0 := by | |
| refine ⟨hx0sol.1, hx0sol.2, ?_⟩ | |
| intro y hy0 hyDelta | |
| dsimp only [x0] | |
| unfold xMinOf | |
| exact csInf_le hBddX ⟨hy0, hyDelta⟩ | |
| have hxdvd : D ∣ x0 := by | |
| exact dvd_of_IsLeastX (D := D) (A := A) (B := B) (K := K) hD hA hB hx0least | |
| let u0 : Int := x0 / D | |
| have hx0eq : x0 = D * u0 := by | |
| calc | |
| x0 = (x0 / D) * D := by | |
| simpa only using (Int.ediv_mul_cancel hxdvd).symm | |
| _ = D * u0 := by | |
| simp only [mul_comm, u0] | |
| have hu0sol : SolU D A B K hD hA hB u0 := by | |
| refine ⟨?_, ?_⟩ | |
| · exact Int.ediv_nonneg hx0sol.1 (le_of_lt hD) | |
| · simpa only [hx0eq] using hx0sol.2 | |
| have huMinSol : SolU D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := by | |
| unfold uMinOf | |
| exact Int.csInf_mem hex hBddU | |
| have huMin_le_u0 : uMinOf D A B K hD hA hB hex ≤ u0 := by | |
| unfold uMinOf | |
| exact csInf_le hBddU hu0sol | |
| have hxOfUmin : SolX D A B K hD hA hB (D * uMinOf D A B K hD hA hB hex) := by | |
| exact ⟨mul_nonneg (le_of_lt hD) huMinSol.1, huMinSol.2⟩ | |
| rcases hx0least with ⟨_hx0nonneg, _hx0Delta, hx0min⟩ | |
| have hx0_le_DuMin : x0 ≤ D * uMinOf D A B K hD hA hB hex := by | |
| exact hx0min (D * uMinOf D A B K hD hA hB hex) hxOfUmin.1 hxOfUmin.2 | |
| have hu0_le_uMin : u0 ≤ uMinOf D A B K hD hA hB hex := by | |
| have hmul : D * u0 ≤ D * uMinOf D A B K hD hA hB hex := by | |
| simpa only [hx0eq] using hx0_le_DuMin | |
| exact (Int.mul_le_mul_left hD).1 hmul | |
| have huEq : u0 = uMinOf D A B K hD hA hB hex := le_antisymm hu0_le_uMin huMin_le_u0 | |
| unfold xMin | |
| simp only [hexX] | |
| calc | |
| xMinOf D A B K hD hA hB hexX = x0 := by rfl | |
| _ = D * u0 := hx0eq | |
| _ = D * uMinOf D A B K hD hA hB hex := by rw [huEq] | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `u` 側に解が存在しないとき `xMin = -1`。 | |
| 内容: 反証法で `∃ x, SolX ... x` を仮定し、`xMinOf` の最小元 `x0` を取る。 | |
| `dvd_of_IsLeastX` から `x0 = D*u0` を得ると `u0` は `SolU` となり `hno` に矛盾する。 | |
| よって `¬ ∃ x, SolX ... x` が従い、`xMin` の定義を `else` 側に簡約する。 | |
| 証明: `csInf_mem`/`csInf_le` と `dvd_of_IsLeastX` による矛盾導出で示す。 | |
| 役割: 非可解ケースの返り値仕様を確定する。 | |
| -/ | |
| lemma xMin_eq_neg_one_of_no_solution | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hno : ¬ ∃ u : Int, SolU D A B K hD hA hB u) : | |
| xMin D A B K hD hA hB = -1 := by | |
| classical | |
| have hnoX : ¬ ∃ x : Int, SolX D A B K hD hA hB x := by | |
| intro hexX | |
| have hBddX : BddBelow ({x : Int | SolX D A B K hD hA hB x} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| let x0 : Int := xMinOf D A B K hD hA hB hexX | |
| have hx0sol : SolX D A B K hD hA hB x0 := by | |
| dsimp only [x0] | |
| unfold xMinOf | |
| exact Int.csInf_mem (by simpa only using hexX) hBddX | |
| have hx0least : IsLeastX D A B K hD hA hB x0 := by | |
| refine ⟨hx0sol.1, hx0sol.2, ?_⟩ | |
| intro y hy0 hyDelta | |
| dsimp only [x0] | |
| unfold xMinOf | |
| exact csInf_le hBddX ⟨hy0, hyDelta⟩ | |
| have hxdvd : D ∣ x0 := by | |
| exact dvd_of_IsLeastX (D := D) (A := A) (B := B) (K := K) hD hA hB hx0least | |
| let u0 : Int := x0 / D | |
| have hx0eq : x0 = D * u0 := by | |
| calc | |
| x0 = (x0 / D) * D := by | |
| simpa only using (Int.ediv_mul_cancel hxdvd).symm | |
| _ = D * u0 := by | |
| simp only [mul_comm, u0] | |
| have hu0sol : SolU D A B K hD hA hB u0 := by | |
| refine ⟨?_, ?_⟩ | |
| · exact Int.ediv_nonneg hx0sol.1 (le_of_lt hD) | |
| · simpa only [hx0eq] using hx0sol.2 | |
| exact hno ⟨u0, hu0sol⟩ | |
| unfold xMin | |
| simp only [hnoX, ↓reduceDIte, Int.reduceNeg] | |
| end NonIncAndSearch | |
| section ExistAndBounds | |
| variable {D A B K u : Int} | |
| /-- | |
| 目的: `g = gcd(D,A)` を `Int` 上で扱う補助定義。 | |
| 定義: `Int.gcd D A` の短い別名を与える。 | |
| 入力/前提: D A : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `R = 0` ケースの条件 `D*K + g < A` と上界 `A/g` で反復利用する。 | |
| -/ | |
| def gcdDA (D A : Int) : Int := | |
| Int.gcd D A | |
| /-- | |
| 目的: `u` 側に解が存在する命題を定義する。 | |
| 定義: `∃ u : Int, SolU D A B K hD hA hB u` を略記する。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 存在定理・上界定理・二分探索正当化の共通仮定を簡潔にする。 | |
| -/ | |
| def HasUSolution | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) : Prop := | |
| ∃ u : Int, SolU D A B K hD hA hB u | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: canonical 形 `A*B*K < ((D*u)%A)*Mof + Rof*u` と `K < Δ` は同値。 | |
| 内容: `lt_Delta_iff_ABK_lt` に `M := Mof`, `R := Rof` を代入して整形する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 後続の存在証明・上界証明で `M`,`R` を明示せず使える形を与える。 | |
| -/ | |
| lemma lt_Delta_iff_ABK_lt_canonical | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hu : 0 ≤ u) | |
| (hK : 0 ≤ K) : | |
| K < Delta D A B (D * u) hD hA hB ↔ | |
| A * B * K < ((D * u) % A) * (Mof D A B) + (Rof D A B) * u := by | |
| simpa only [Mof, Rof] using | |
| (lt_Delta_iff_ABK_lt (D := D) (A := A) (B := B) (K := K) (u := u) (M := Mof D A B) (R := | |
| Rof D A B) hD hA hB hu hK rfl rfl) | |
| /-- | |
| 入力/前提: hA : 0 < A、_hu : 0 ≤ u。 | |
| 主張: `0 ≤ (D*u)%A ≤ A - gcd(D,A)`。 | |
| 内容: 余りの範囲 `0 ≤ r < A` と `gcd(D,A)` が `r` を割る事実から上界 `r ≤ A-g` を導く。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `R = 0` での必要条件導出と上界評価の鍵となる剰余評価。 | |
| -/ | |
| lemma Du_mod_A_bounds_with_gcd | |
| (hA : 0 < A) | |
| (_hu : 0 ≤ u) : | |
| 0 ≤ (D * u) % A ∧ (D * u) % A ≤ A - gcdDA D A := by | |
| let g : Int := gcdDA D A | |
| let r : Int := (D * u) % A | |
| have hA0 : A ≠ 0 := ne_of_gt hA | |
| have hr0 : 0 ≤ r := by | |
| simpa only using Int.emod_nonneg (D * u) hA0 | |
| have hrlt : r < A := by | |
| simpa only using Int.emod_lt_of_pos (D * u) hA | |
| have hgD : g ∣ D := by | |
| simpa only [gcdDA] using (Int.gcd_dvd_left D A) | |
| have hgA : g ∣ A := by | |
| simpa only [gcdDA] using (Int.gcd_dvd_right D A) | |
| have hgDu : g ∣ D * u := dvd_mul_of_dvd_left hgD u | |
| have hgAq : g ∣ A * ((D * u) / A) := dvd_mul_of_dvd_left hgA ((D * u) / A) | |
| have hrEq : r = D * u - A * ((D * u) / A) := by | |
| have hdecomp : A * ((D * u) / A) + r = D * u := by | |
| simpa only using (Int.mul_ediv_add_emod (D * u) A) | |
| omega | |
| have hgr : g ∣ r := by | |
| rw [hrEq] | |
| exact dvd_sub hgDu hgAq | |
| have hdiffPos : 0 < A - r := by | |
| exact sub_pos.mpr hrlt | |
| have hgDiff : g ∣ A - r := dvd_sub hgA hgr | |
| have hgLe : g ≤ A - r := Int.le_of_dvd hdiffPos hgDiff | |
| have hrLe : r ≤ A - g := by | |
| omega | |
| exact ⟨by simpa only [r] using hr0, by simpa only [gcdDA, r, g] using hrLe⟩ | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `Rof D A B ≠ 0` なら `HasUSolution` が成り立つ。 | |
| 内容: 候補 `u0 = A*B*K + 1` を取り、`R*u0 > A*B*K` と非負項 `((D*u0)%A)*M` で canonical 不等式を満たす。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `R ≠ 0` ケースの存在性を一発で与える。 | |
| -/ | |
| lemma exists_u_of_R_ne_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hRnz : Rof D A B ≠ 0) : | |
| HasUSolution D A B K hD hA hB := by | |
| let u0 : Int := A * B * K + 1 | |
| have hABpos : 0 < A * B := Int.mul_pos hA hB | |
| have hABK0 : 0 ≤ A * B * K := mul_nonneg (le_of_lt hABpos) hK | |
| have hu0 : 0 ≤ u0 := by | |
| dsimp only [u0] | |
| omega | |
| have hR0 : 0 ≤ Rof D A B := by | |
| simpa only [Rof] using Int.emod_nonneg (A * B) (ne_of_gt hD) | |
| have hRpos : 0 < Rof D A B := lt_of_le_of_ne hR0 (by symm; exact hRnz) | |
| have hRge1 : (1 : Int) ≤ Rof D A B := (Int.lt_iff_add_one_le).1 hRpos | |
| have hM0 : 0 ≤ Mof D A B := by | |
| unfold Mof | |
| exact Int.ediv_nonneg (le_of_lt hABpos) (le_of_lt hD) | |
| have hterm0 : 0 ≤ ((D * u0) % A) * Mof D A B := by | |
| refine mul_nonneg ?_ hM0 | |
| exact Int.emod_nonneg (D * u0) (ne_of_gt hA) | |
| have hABK_lt_u0 : A * B * K < u0 := by | |
| dsimp only [u0] | |
| omega | |
| have hu0_le_Ru0 : u0 ≤ Rof D A B * u0 := by | |
| calc | |
| u0 = 1 * u0 := by ring | |
| _ ≤ Rof D A B * u0 := mul_le_mul_of_nonneg_right hRge1 hu0 | |
| have hABK_lt_Ru0 : A * B * K < Rof D A B * u0 := lt_of_lt_of_le hABK_lt_u0 hu0_le_Ru0 | |
| have hRu0_le_rhs : | |
| Rof D A B * u0 ≤ ((D * u0) % A) * Mof D A B + Rof D A B * u0 := by | |
| exact le_add_of_nonneg_left hterm0 | |
| have hABK_lt_rhs : | |
| A * B * K < ((D * u0) % A) * Mof D A B + Rof D A B * u0 := by | |
| exact lt_of_lt_of_le hABK_lt_Ru0 hRu0_le_rhs | |
| refine ⟨u0, hu0, ?_⟩ | |
| exact | |
| (lt_Delta_iff_ABK_lt_canonical | |
| (D := D) (A := A) (B := B) (K := K) (u := u0) | |
| hD hA hB hu0 hK).2 hABK_lt_rhs | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `R = 0` かつ `D*K + gcd(D,A) < A` なら `u < A/g` の可解 `u` が存在する。 | |
| 内容: `D=gD1`, `A=gA1` に分解し Bézout 由来の `u` を構成して `(D*u)%A = A-g` を実現する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `R = 0` ケースの十分条件と具体的候補を与える中心補題。 | |
| -/ | |
| lemma exists_solU_lt_A_div_g_of_R_eq_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) | |
| (hcond : D * K + gcdDA D A < A) : | |
| ∃ u : Int, SolU D A B K hD hA hB u ∧ u < A / gcdDA D A := by | |
| let g : Int := gcdDA D A | |
| let D1 : Int := D / g | |
| let A1 : Int := A / g | |
| have hg0 : 0 < g := by | |
| have : 0 < Int.gcd D A := Int.gcd_pos_of_ne_zero_right D (ne_of_gt hA) | |
| simpa only [g, gcdDA, Int.natCast_pos, Int.gcd_pos_iff, ne_eq] using this | |
| have hgD : g ∣ D := by | |
| simpa only [gcdDA] using (Int.gcd_dvd_left D A) | |
| have hgA : g ∣ A := by | |
| simpa only [gcdDA] using (Int.gcd_dvd_right D A) | |
| have hDsplit : D = g * D1 := by | |
| have h : D / g * g = D := Int.ediv_mul_cancel hgD | |
| have h' : g * D1 = D := by simpa only [mul_comm] using h | |
| exact h'.symm | |
| have hAsplit : A = g * A1 := by | |
| have h : A / g * g = A := Int.ediv_mul_cancel hgA | |
| have h' : g * A1 = A := by simpa only [mul_comm] using h | |
| exact h'.symm | |
| have hA1pos : 0 < A1 := by | |
| have hprod : 0 < A1 * g := by | |
| calc | |
| 0 < A := hA | |
| _ = g * A1 := hAsplit | |
| _ = A1 * g := by ring | |
| exact Int.pos_of_mul_pos_left hprod hg0 | |
| have hgNatPos : 0 < Int.gcd D A := Int.gcd_pos_of_ne_zero_right D (ne_of_gt hA) | |
| have hcop : Int.gcd D1 A1 = 1 := by | |
| simpa only [gcdDA] using (Int.gcd_div_gcd_div_gcd (i := D) (j := A) hgNatPos) | |
| have hbez : (1 : Int) = D1 * Int.gcdA D1 A1 + A1 * Int.gcdB D1 A1 := by | |
| simpa only [hcop, Nat.cast_one] using (Int.gcd_eq_gcd_ab D1 A1) | |
| let u : Int := (-Int.gcdA D1 A1) % A1 | |
| have hu0 : 0 ≤ u := by | |
| dsimp only [u] | |
| exact Int.emod_nonneg _ (ne_of_gt hA1pos) | |
| have huLtA1 : u < A1 := by | |
| dsimp only [u] | |
| exact Int.emod_lt_of_pos _ hA1pos | |
| have hmodU : u ≡ -Int.gcdA D1 A1 [ZMOD A1] := by | |
| dsimp only [u] | |
| simpa only using (Int.mod_modEq (-Int.gcdA D1 A1) A1) | |
| have hmodMul : D1 * u ≡ D1 * (-Int.gcdA D1 A1) [ZMOD A1] := | |
| Int.ModEq.mul_left D1 hmodU | |
| have hmodNeg1 : D1 * (-Int.gcdA D1 A1) ≡ (-1) [ZMOD A1] := by | |
| have hbezNeg : (-1 : Int) = D1 * (-Int.gcdA D1 A1) + A1 * (-Int.gcdB D1 A1) := by | |
| have hneg := congrArg (fun t : Int => -t) hbez | |
| calc | |
| (-1 : Int) = -(D1 * Int.gcdA D1 A1 + A1 * Int.gcdB D1 A1) := by simpa only [Int.reduceNeg, | |
| neg_add_rev] using hneg | |
| _ = D1 * (-Int.gcdA D1 A1) + A1 * (-Int.gcdB D1 A1) := by ring | |
| refine (Int.modEq_iff_dvd).2 ?_ | |
| refine ⟨-Int.gcdB D1 A1, ?_⟩ | |
| omega | |
| have hmodFinal : D1 * u ≡ (-1) [ZMOD A1] := hmodMul.trans hmodNeg1 | |
| have hremA1 : (D1 * u) % A1 = (-1) % A1 := hmodFinal.eq | |
| have hneg1 : (-1) % A1 = A1 - 1 := by | |
| simpa only [Int.reduceNeg, Int.reduceNegSucc, CharP.cast_eq_zero, EuclideanDomain.zero_mod, | |
| sub_zero] using (Int.negSucc_emod 0 hA1pos) | |
| have hremA1' : (D1 * u) % A1 = A1 - 1 := by | |
| simpa only [Int.reduceNeg, hneg1] using hremA1 | |
| have hrem : (D * u) % A = A - g := by | |
| calc | |
| (D * u) % A = (g * (D1 * u)) % (g * A1) := by | |
| rw [hDsplit, hAsplit] | |
| ring_nf | |
| _ = g * ((D1 * u) % A1) := Int.mul_emod_mul_of_pos (a := g) (b := D1 * u) (c := A1) hg0 | |
| _ = g * (A1 - 1) := by rw [hremA1'] | |
| _ = A - g := by | |
| calc | |
| g * (A1 - 1) = g * A1 - g := by ring | |
| _ = A - g := by rw [hAsplit] | |
| have hDM_eq_AB : D * Mof D A B = A * B := by | |
| have hdecomp : D * ((A * B) / D) + (A * B) % D = A * B := Int.mul_ediv_add_emod (A * B) D | |
| have hmod0 : (A * B) % D = 0 := by simpa only [EuclideanDomain.mod_eq_zero, Rof] using hR0 | |
| have hmain : D * ((A * B) / D) = A * B := by omega | |
| simpa only [Mof] using hmain | |
| have hABeqDM : A * B = D * Mof D A B := hDM_eq_AB.symm | |
| have hABpos : 0 < A * B := Int.mul_pos hA hB | |
| have hMpos : 0 < Mof D A B := by | |
| have hprod : 0 < D * Mof D A B := by simpa only [hDM_eq_AB] using hABpos | |
| have hprod' : 0 < Mof D A B * D := by simpa only [mul_comm] using hprod | |
| exact Int.pos_of_mul_pos_left hprod' hD | |
| have hDK_lt_Ag : D * K < A - g := by | |
| omega | |
| have hABK_lt_bound : A * B * K < (A - g) * Mof D A B := by | |
| have hmul : (D * K) * Mof D A B < (A - g) * Mof D A B := | |
| (Int.mul_lt_mul_right hMpos).2 hDK_lt_Ag | |
| calc | |
| A * B * K = (D * K) * Mof D A B := by | |
| rw [hABeqDM] | |
| ring | |
| _ < (A - g) * Mof D A B := hmul | |
| have hABK_lt_rhs : | |
| A * B * K < ((D * u) % A) * Mof D A B + Rof D A B * u := by | |
| calc | |
| A * B * K < (A - g) * Mof D A B := hABK_lt_bound | |
| _ = ((D * u) % A) * Mof D A B := by rw [hrem] | |
| _ = ((D * u) % A) * Mof D A B + Rof D A B * u := by simp only [hR0, zero_mul, add_zero] | |
| have huDelta : K < Delta D A B (D * u) hD hA hB := by | |
| exact | |
| (lt_Delta_iff_ABK_lt_canonical | |
| (D := D) (A := A) (B := B) (K := K) (u := u) | |
| hD hA hB hu0 hK).2 hABK_lt_rhs | |
| have huLtDiv : u < A / g := by | |
| simpa only using huLtA1 | |
| exact ⟨u, ⟨hu0, huDelta⟩, by simpa only [gcdDA, g] using huLtDiv⟩ | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `R = 0` のとき `HasUSolution ↔ D*K + gcd(D,A) < A`。 | |
| 内容: `→` は `Du_mod_A_bounds_with_gcd` で必要条件を示し、`←` は具体解構成補題を使う。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: LaTeX の存在条件(`lem:exist`)を Lean で同値として確定する。 | |
| -/ | |
| lemma exists_u_iff_DK_add_g_lt_A_of_R_eq_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) : | |
| HasUSolution D A B K hD hA hB ↔ D * K + gcdDA D A < A := by | |
| let g : Int := gcdDA D A | |
| have hDM_eq_AB : D * Mof D A B = A * B := by | |
| have hdecomp : D * ((A * B) / D) + (A * B) % D = A * B := Int.mul_ediv_add_emod (A * B) D | |
| have hmod0 : (A * B) % D = 0 := by simpa only [EuclideanDomain.mod_eq_zero, Rof] using hR0 | |
| have hmain : D * ((A * B) / D) = A * B := by omega | |
| simpa only [Mof] using hmain | |
| have hABeqDM : A * B = D * Mof D A B := hDM_eq_AB.symm | |
| have hABpos : 0 < A * B := Int.mul_pos hA hB | |
| have hMpos : 0 < Mof D A B := by | |
| have hprod : 0 < D * Mof D A B := by simpa only [hDM_eq_AB] using hABpos | |
| have hprod' : 0 < Mof D A B * D := by simpa only [mul_comm] using hprod | |
| exact Int.pos_of_mul_pos_left hprod' hD | |
| constructor | |
| · intro hsol | |
| rcases hsol with ⟨u, hu0, huDelta⟩ | |
| have hABK_lt_rhs : | |
| A * B * K < ((D * u) % A) * Mof D A B + Rof D A B * u := by | |
| exact | |
| (lt_Delta_iff_ABK_lt_canonical | |
| (D := D) (A := A) (B := B) (K := K) (u := u) | |
| hD hA hB hu0 hK).1 huDelta | |
| have hABK_lt_remM : A * B * K < ((D * u) % A) * Mof D A B := by | |
| simpa only [hR0, zero_mul, add_zero] using hABK_lt_rhs | |
| have hrem_le : (D * u) % A ≤ A - g := by | |
| exact (Du_mod_A_bounds_with_gcd (D := D) (A := A) (u := u) hA hu0).2 | |
| have hMnonneg : 0 ≤ Mof D A B := le_of_lt hMpos | |
| have hremM_le : ((D * u) % A) * Mof D A B ≤ (A - g) * Mof D A B := by | |
| exact mul_le_mul_of_nonneg_right hrem_le hMnonneg | |
| have hABK_lt_bound : A * B * K < (A - g) * Mof D A B := lt_of_lt_of_le hABK_lt_remM hremM_le | |
| have hmul : (D * K) * Mof D A B < (A - g) * Mof D A B := by | |
| calc | |
| (D * K) * Mof D A B = A * B * K := by | |
| rw [hABeqDM] | |
| ring | |
| _ < (A - g) * Mof D A B := hABK_lt_bound | |
| have hDK_lt_Ag : D * K < A - g := (Int.mul_lt_mul_right hMpos).1 hmul | |
| have : D * K + g < A := by omega | |
| simpa only [gcdDA, gt_iff_lt] using this | |
| · intro hcond | |
| rcases exists_solU_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond with | |
| ⟨u, huSol, _huLt⟩ | |
| exact ⟨u, huSol⟩ | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 解があるなら `uMinOf ≥ K + 1`。 | |
| 内容: 任意可解 `b` について `Δ(D,A,B,D*b) ≤ b` から `K < b` を導き `K+1 ≤ b` を得る。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 探索区間の下界と最小解の基本的性質を与える。 | |
| -/ | |
| lemma uMin_lower_bound | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| (K + 1 : Int) ≤ uMinOf D A B K hD hA hB hex := by | |
| unfold uMinOf | |
| refine le_csInf ?_ ?_ | |
| · rcases hex with ⟨u, hu⟩ | |
| exact ⟨u, hu⟩ | |
| intro b hb | |
| rcases hb with ⟨hb0, hbK⟩ | |
| have hM0 : 0 ≤ Mof D A B := by | |
| unfold Mof | |
| exact Int.ediv_nonneg (le_of_lt (Int.mul_pos hA hB)) (le_of_lt hD) | |
| have hDb0 : 0 ≤ D * b := mul_nonneg (le_of_lt hD) hb0 | |
| have hDiv0 : 0 ≤ (D * b) / A := Int.ediv_nonneg hDb0 (le_of_lt hA) | |
| have hSub0 : 0 ≤ ((Mof D A B * ((D * b) / A)) / B) := by | |
| exact Int.ediv_nonneg (mul_nonneg hM0 hDiv0) (le_of_lt hB) | |
| have hDelta_le : Delta D A B (D * b) hD hA hB ≤ b := by | |
| have hrew : | |
| Delta D A B (D * b) hD hA hB = | |
| b - ((Mof D A B * ((D * b) / A)) / B) := by | |
| simpa only [Mof] using | |
| (Delta_Du_rewrite (D := D) (A := A) (B := B) (u := b) (M := Mof D A B) hD hA hB hb0 rfl) | |
| rw [hrew] | |
| exact sub_le_self _ hSub0 | |
| have hKltb : K < b := lt_of_lt_of_le hbK hDelta_le | |
| exact (Int.add_one_le_iff).2 hKltb | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `R = 0` かつ `D*K + gcd(D,A) < A` なら `uMinOf < A / gcd(D,A)`。 | |
| 内容: `u < A/g` の可解候補を取り、`sInf ≤ u` から最小解の上界へ落とす。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `R = 0` ケースの探索上界を与える。 | |
| -/ | |
| lemma uMin_lt_A_div_g_of_R_eq_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) | |
| (hcond : D * K + gcdDA D A < A) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| uMinOf D A B K hD hA hB hex < A / gcdDA D A := by | |
| rcases exists_solU_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond with | |
| ⟨u, huSol, huLt⟩ | |
| have hBdd : BddBelow ({z : Int | SolU D A B K hD hA hB z} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| have hInfLe : | |
| sInf ({z : Int | SolU D A B K hD hA hB z} : Set Int) ≤ u := csInf_le hBdd huSol | |
| unfold uMinOf | |
| exact lt_of_le_of_lt hInfLe huLt | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `R ≠ 0` なら `uMinOf < (A*B*K)/R + 2`。 | |
| 内容: `u0 = (A*B*K)/R + 1` を可解候補として構成し、`sInf ≤ u0 < ... + 2` を示す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `R ≠ 0` ケースの探索上界を与える。 | |
| -/ | |
| lemma uMin_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hRnz : Rof D A B ≠ 0) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| uMinOf D A B K hD hA hB hex < (A * B * K) / (Rof D A B) + 2 := by | |
| let u0 : Int := (A * B * K) / (Rof D A B) + 1 | |
| have hABpos : 0 < A * B := Int.mul_pos hA hB | |
| have hABK0 : 0 ≤ A * B * K := mul_nonneg (le_of_lt hABpos) hK | |
| have hR0 : 0 ≤ Rof D A B := by | |
| simpa only [Rof] using Int.emod_nonneg (A * B) (ne_of_gt hD) | |
| have hRpos : 0 < Rof D A B := lt_of_le_of_ne hR0 (by symm; exact hRnz) | |
| have hu0 : 0 ≤ u0 := by | |
| have hdiv0 : 0 ≤ (A * B * K) / (Rof D A B) := Int.ediv_nonneg hABK0 hR0 | |
| dsimp only [u0] | |
| omega | |
| have hM0 : 0 ≤ Mof D A B := by | |
| unfold Mof | |
| exact Int.ediv_nonneg (le_of_lt hABpos) (le_of_lt hD) | |
| have hterm0 : 0 ≤ ((D * u0) % A) * Mof D A B := by | |
| refine mul_nonneg ?_ hM0 | |
| exact Int.emod_nonneg (D * u0) (ne_of_gt hA) | |
| have hABK_lt_Ru0 : A * B * K < Rof D A B * u0 := by | |
| have hlt : | |
| A * B * K < ((A * B * K) / (Rof D A B) + 1) * Rof D A B := by | |
| exact (Int.ediv_lt_iff_lt_mul hRpos).1 (lt_add_one ((A * B * K) / (Rof D A B))) | |
| simpa only [u0, mul_comm, mul_left_comm, gt_iff_lt] using hlt | |
| have hRu0_le_rhs : | |
| Rof D A B * u0 ≤ ((D * u0) % A) * Mof D A B + Rof D A B * u0 := by | |
| exact le_add_of_nonneg_left hterm0 | |
| have hABK_lt_rhs : | |
| A * B * K < ((D * u0) % A) * Mof D A B + Rof D A B * u0 := by | |
| exact lt_of_lt_of_le hABK_lt_Ru0 hRu0_le_rhs | |
| have hCand : u0 ∈ ({u : Int | SolU D A B K hD hA hB u} : Set Int) := by | |
| refine ⟨hu0, ?_⟩ | |
| exact | |
| (lt_Delta_iff_ABK_lt_canonical | |
| (D := D) (A := A) (B := B) (K := K) (u := u0) | |
| hD hA hB hu0 hK).2 hABK_lt_rhs | |
| have hBdd : BddBelow ({u : Int | SolU D A B K hD hA hB u} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| have hInfLe : | |
| sInf ({u : Int | SolU D A B K hD hA hB u} : Set Int) ≤ u0 := csInf_le hBdd hCand | |
| have hu0_lt : u0 < (A * B * K) / (Rof D A B) + 2 := by | |
| dsimp only [u0] | |
| omega | |
| unfold uMinOf | |
| exact lt_of_le_of_lt hInfLe hu0_lt | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 可解なら常に粗い共通上界 `uMinOf < A*B*K + 2`。 | |
| 内容: `R = 0` / `R ≠ 0`(さらに `K = 0` / `K > 0`)で分岐し既存の鋭い上界を統合する。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 場合分け不要で使える初期探索上界を提供する。 | |
| -/ | |
| lemma uMin_lt_ABK_plus_two | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| uMinOf D A B K hD hA hB hex < A * B * K + 2 := by | |
| by_cases hR0 : Rof D A B = 0 | |
| · have hcond : D * K + gcdDA D A < A := by | |
| exact | |
| (exists_u_iff_DK_add_g_lt_A_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0).1 hex | |
| by_cases hK0 : K = 0 | |
| · have hA0 : A ≠ 0 := ne_of_gt hA | |
| have hglt : gcdDA D A < A := by | |
| simpa only [hK0, mul_zero, zero_add] using hcond | |
| have hNotDvd : ¬ A ∣ D := by | |
| intro hAdvd | |
| have hgEq : gcdDA D A = A := by | |
| simpa only [gcdDA] using (Int.gcd_eq_right (le_of_lt hA) hAdvd) | |
| have : A < A := by | |
| have hglt' := hglt | |
| rw [hgEq] at hglt' | |
| exact hglt' | |
| exact (lt_irrefl A) this | |
| have hDmodNe : D % A ≠ 0 := by | |
| intro hmod | |
| apply hNotDvd | |
| exact (Int.dvd_iff_emod_eq_zero).2 hmod | |
| have hDmodPos : 0 < D % A := by | |
| have hDmod0 : 0 ≤ D % A := Int.emod_nonneg _ hA0 | |
| exact lt_of_le_of_ne hDmod0 hDmodNe.symm | |
| have hABpos : 0 < A * B := Int.mul_pos hA hB | |
| have hDM : D * Mof D A B = A * B := by | |
| have hdecomp : D * ((A * B) / D) + (A * B) % D = A * B := Int.mul_ediv_add_emod (A * B) D | |
| have hmod0 : (A * B) % D = 0 := by simpa only [EuclideanDomain.mod_eq_zero, Rof] using hR0 | |
| have : D * ((A * B) / D) = A * B := by | |
| omega | |
| simpa only [Mof] using this | |
| have hMpos : 0 < Mof D A B := by | |
| have hprod : 0 < D * Mof D A B := by simpa only [hDM] using hABpos | |
| have hprod' : 0 < Mof D A B * D := by simpa only [mul_comm] using hprod | |
| exact Int.pos_of_mul_pos_left hprod' hD | |
| have hOneSol : SolU D A B K hD hA hB 1 := by | |
| refine ⟨by decide, ?_⟩ | |
| have hABK_lt_rhs : | |
| A * B * K < | |
| ((D * (1 : Int)) % A) * Mof D A B + Rof D A B * (1 : Int) := by | |
| have hposRhs : 0 < (D % A) * Mof D A B := Int.mul_pos hDmodPos hMpos | |
| have hposRhs' : 0 < ((D * (1 : Int)) % A) * Mof D A B + Rof D A B * (1 : Int) := by | |
| simpa only [mul_one, hR0, add_zero] using hposRhs | |
| have hABK0 : A * B * K = 0 := by simp only [hK0, mul_zero] | |
| simpa only [hABK0, mul_one, gt_iff_lt] using hposRhs' | |
| exact | |
| (lt_Delta_iff_ABK_lt_canonical | |
| (D := D) (A := A) (B := B) (K := K) (u := 1) | |
| hD hA hB (by decide) hK).2 hABK_lt_rhs | |
| have hBdd : BddBelow ({u : Int | SolU D A B K hD hA hB u} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| have hInfLe1 : | |
| sInf ({u : Int | SolU D A B K hD hA hB u} : Set Int) ≤ 1 := | |
| csInf_le hBdd hOneSol | |
| have hlt2 : | |
| sInf ({u : Int | SolU D A B K hD hA hB u} : Set Int) < 2 := | |
| lt_of_le_of_lt hInfLe1 (by decide) | |
| have hgoal2 : A * B * K + 2 = 2 := by simp only [hK0, mul_zero, zero_add] | |
| unfold uMinOf | |
| simpa only [hgoal2, gt_iff_lt] using hlt2 | |
| · have hKpos : 0 < K := by | |
| have h0ne : 0 ≠ K := by | |
| intro h0 | |
| apply hK0 | |
| exact h0.symm | |
| exact lt_of_le_of_ne hK h0ne | |
| have hltAdiv : | |
| uMinOf D A B K hD hA hB hex < A / gcdDA D A := by | |
| exact | |
| uMin_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond hex | |
| have hAdiv_le_A : A / gcdDA D A ≤ A := Int.ediv_le_self (gcdDA D A) (le_of_lt hA) | |
| have hA_le_ABK : A ≤ A * B * K := by | |
| have hA_le_AB : A ≤ A * B := by | |
| have hBge1 : (1 : Int) ≤ B := (Int.lt_iff_add_one_le).1 hB | |
| simpa only [ge_iff_le, mul_one] using mul_le_mul_of_nonneg_left hBge1 (le_of_lt hA) | |
| have hKge1 : (1 : Int) ≤ K := (Int.lt_iff_add_one_le).1 hKpos | |
| have hAB_le_ABK : A * B ≤ A * B * K := by | |
| simpa only [mul_assoc, mul_one] using | |
| mul_le_mul_of_nonneg_left hKge1 (mul_nonneg (le_of_lt hA) (le_of_lt hB)) | |
| exact le_trans hA_le_AB hAB_le_ABK | |
| have hAdiv_le_ABK1 : A / gcdDA D A ≤ A * B * K + 1 := by | |
| exact le_trans hAdiv_le_A (by omega) | |
| have hltABK1 : uMinOf D A B K hD hA hB hex < A * B * K + 1 := by | |
| exact lt_of_lt_of_le hltAdiv hAdiv_le_ABK1 | |
| exact lt_of_lt_of_le hltABK1 (by omega) | |
| · have hlt : | |
| uMinOf D A B K hD hA hB hex < (A * B * K) / (Rof D A B) + 2 := by | |
| exact | |
| uMin_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hex | |
| have hABK0 : 0 ≤ A * B * K := mul_nonneg (le_of_lt (Int.mul_pos hA hB)) hK | |
| have hdivLe : (A * B * K) / (Rof D A B) ≤ A * B * K := | |
| Int.ediv_le_self (Rof D A B) hABK0 | |
| have hplusLe : (A * B * K) / (Rof D A B) + 2 ≤ A * B * K + 2 := by | |
| simpa only [add_le_add_iff_right] using add_le_add_left hdivLe 2 | |
| exact lt_of_lt_of_le hlt hplusLe | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 可解性条件と最小解上界を一括で与える総合定理。 | |
| 内容: `R ≠ 0` の存在性、`R = 0` の同値条件、および `uMinOf` の各種上界を同時に返す。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 本文 `lem:exist` に対応する統合インターフェース。 | |
| -/ | |
| theorem exist_and_search_upper_bound | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) : | |
| (Rof D A B ≠ 0 → HasUSolution D A B K hD hA hB) ∧ | |
| (Rof D A B = 0 → | |
| (HasUSolution D A B K hD hA hB ↔ D * K + gcdDA D A < A)) ∧ | |
| (∀ hex : HasUSolution D A B K hD hA hB, | |
| (Rof D A B = 0 → | |
| uMinOf D A B K hD hA hB hex < A / gcdDA D A) ∧ | |
| (Rof D A B ≠ 0 → | |
| uMinOf D A B K hD hA hB hex < (A * B * K) / (Rof D A B) + 2) ∧ | |
| uMinOf D A B K hD hA hB hex < A * B * K + 2) := by | |
| constructor | |
| · intro hRnz | |
| exact exists_u_of_R_ne_zero (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz | |
| constructor | |
| · intro hR0 | |
| exact | |
| exists_u_iff_DK_add_g_lt_A_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 | |
| · intro hex | |
| constructor | |
| · intro hR0 | |
| have hcond : D * K + gcdDA D A < A := by | |
| exact | |
| (exists_u_iff_DK_add_g_lt_A_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0).1 hex | |
| exact | |
| uMin_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond hex | |
| constructor | |
| · intro hRnz | |
| exact | |
| uMin_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz hex | |
| · exact uMin_lt_ABK_plus_two (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex | |
| end ExistAndBounds | |
| section BinarySearchMinSketch | |
| open MWF | |
| variable {D A B K L R n N X u : Int} | |
| /-- | |
| 目的: 二分探索で使う評価関数 `f(u)` を定義する。 | |
| 定義: `f(u) = B*u - Mof*⌊D*u/A⌋`。 | |
| 入力/前提: D A B : Int、u : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `K < Δ` 判定を `B*K < f(u)` に写し、区間最大化 `F(L,R)` に接続する。 | |
| -/ | |
| def fBinary (D A B : Int) (u : Int) : Int := | |
| B * u - (Mof D A B) * ((D * u) / A) | |
| /-- | |
| 目的: 区間 `[L,R)` で `B*K < f(u)` を満たす点が無いことを述語化する。 | |
| 定義: すべての `u` について `fBinary D A B u ≤ B*K` を要求する。 | |
| 入力/前提: D A B K : Int、L R : Int。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: `F(L,R) ≤ B*K` を二分探索不変量として扱うための述語版。 | |
| -/ | |
| def NoHitBK (D A B K : Int) (L R : Int) : Prop := | |
| ∀ u : Int, L ≤ u → u < R → fBinary D A B u ≤ B * K | |
| /-- | |
| 目的: 区間 `[L,R)` で `K < Δ(D,A,B,D*u)` が成立しないことを述語化する。 | |
| 定義: すべての `u` に対して `¬ (K < Delta ... (D*u))` を課す。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: `NoHitBK` と同値化して `Δ` 側判定と探索手続きをつなぐ。 | |
| -/ | |
| def NoHitDelta | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (L R : Int) : Prop := | |
| ∀ u : Int, L ≤ u → u < R → ¬ (K < Delta D A B (D * u) hD hA hB) | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `K < Δ(D,A,B,D*u)` と `B*K < fBinary D A B u` は同値。 | |
| 内容: `lt_Delta_iff_BK_lt` に `M := Mof` を代入して `fBinary` 表現へ移す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `NoHitDelta` と `NoHitBK` の橋渡しとなる点wise同値。 | |
| -/ | |
| lemma lt_Delta_iff_BK_lt_fBinary | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hu : 0 ≤ u) | |
| (hK : 0 ≤ K) : | |
| K < Delta D A B (D * u) hD hA hB ↔ B * K < fBinary D A B u := by | |
| simpa only [fBinary] using | |
| (lt_Delta_iff_BK_lt (D := D) (A := A) (B := B) (K := K) (u := u) (M := Mof D A B) hD hA hB hu hK | |
| rfl) | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `L ≥ 0` の範囲で `NoHitDelta ... L R ↔ NoHitBK ... L R`。 | |
| 内容: 各 `u` で `lt_Delta_iff_BK_lt_fBinary` を適用し、否定付き述語へ持ち上げる。 | |
| 証明: 反証法で示す。 | |
| 役割: 二分探索不変量を `Δ` 版と `f` 版のどちらでも扱えるようにする。 | |
| -/ | |
| lemma NoHitDelta_iff_NoHitBK | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hL0 : 0 ≤ L) : | |
| NoHitDelta D A B K hD hA hB L R ↔ NoHitBK D A B K L R := by | |
| constructor | |
| · intro hNoDelta u hLu huR | |
| by_contra hge | |
| have hu0 : 0 ≤ u := le_trans hL0 hLu | |
| have hgt : B * K < fBinary D A B u := lt_of_not_ge hge | |
| have hDelta : K < Delta D A B (D * u) hD hA hB := by | |
| exact | |
| (lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := u) | |
| hD hA hB hu0 hK).2 hgt | |
| exact (hNoDelta u hLu huR) hDelta | |
| · intro hNoBK u hLu huR hDelta | |
| have hu0 : 0 ≤ u := le_trans hL0 hLu | |
| have hgt : B * K < fBinary D A B u := by | |
| exact | |
| (lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := u) | |
| hD hA hB hu0 hK).1 hDelta | |
| exact not_lt_of_ge (hNoBK u hLu huR) hgt | |
| /-- | |
| 入力/前提: hnN : n ≤ N、hNo : NoHitBK D A B K 0 N。 | |
| 主張: `NoHitBK ... 0 N` が成り立てば、右端を縮めた `NoHitBK ... 0 n` も成り立つ。 | |
| 内容: `u < n ≤ N` から `u < N` を得て元の仮定を適用する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 区間最大の単調性(prefix 安全性)を述語で使う補題。 | |
| -/ | |
| lemma NoHitBK_mono_right | |
| (hnN : n ≤ N) | |
| (hNo : NoHitBK D A B K 0 N) : | |
| NoHitBK D A B K 0 n := by | |
| intro u hu0 hun | |
| exact hNo u hu0 (lt_of_lt_of_le hun hnN) | |
| /-- | |
| 入力/前提: hn0 : 0 ≤ n、_hnN : n ≤ N、hPrefix : NoHitBK D A B K 0 n。 | |
| 主張: `NoHitBK ... 0 n` を仮定すると `NoHitBK ... 0 N ↔ NoHitBK ... n N`。 | |
| 内容: `u < n` と `n ≤ u` の場合分けで prefix / suffix を貼り合わせる。 | |
| 証明: 場合分けで示す。 | |
| 役割: 二分探索で「前半が安全なら後半だけ判定すればよい」を形式化する。 | |
| -/ | |
| lemma NoHitBK_prefix_iff_suffix | |
| (hn0 : 0 ≤ n) | |
| (_hnN : n ≤ N) | |
| (hPrefix : NoHitBK D A B K 0 n) : | |
| NoHitBK D A B K 0 N ↔ NoHitBK D A B K n N := by | |
| constructor | |
| · intro hAll u hnu huN | |
| have hu0 : 0 ≤ u := le_trans hn0 hnu | |
| exact hAll u hu0 huN | |
| · intro hSuf u hu0 huN | |
| by_cases huLt : u < n | |
| · exact hPrefix u hu0 huLt | |
| · have hnu : n ≤ u := le_of_not_gt huLt | |
| exact hSuf u hnu huN | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `uMinOf` は可解集合 `{u | SolU ... u}` に属する。 | |
| 内容: 可解集合の下方有界性と `Int.csInf_mem` を使って示す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `uMinOf` 自身を具体的な可解点として使うための基本補題。 | |
| -/ | |
| lemma uMinOf_mem | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| SolU D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := by | |
| have hBdd : BddBelow ({u : Int | SolU D A B K hD hA hB u} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| unfold uMinOf | |
| exact Int.csInf_mem (by simpa only [HasUSolution] using hex) hBdd | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 任意の可解 `u` に対して `uMinOf ≤ u`。 | |
| 内容: 可解集合の下方有界性の下で `csInf_le` を適用する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `uMinOf` の最小性を不等式として使うための補助補題。 | |
| -/ | |
| lemma uMinOf_le_of_sol | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| {u : Int} | |
| (hu : SolU D A B K hD hA hB u) : | |
| uMinOf D A B K hD hA hB hex ≤ u := by | |
| have hBdd : BddBelow ({z : Int | SolU D A B K hD hA hB z} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| unfold uMinOf | |
| exact csInf_le hBdd hu | |
| /-- | |
| 目的: `Nmax` が「`NoHitDelta 0 N` を満たす最大の `N`」である仕様を定義する。 | |
| 定義: 非負性・`NoHitDelta 0 Nmax`・最大性(任意 `N` は `N ≤ Nmax`)を束ねる。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 二分探索が満たすべき仕様を数学的に固定する。 | |
| -/ | |
| def NmaxSpec | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (Nmax : Int) : Prop := | |
| 0 ≤ Nmax ∧ | |
| NoHitDelta D A B K hD hA hB 0 Nmax ∧ | |
| ∀ N : Int, 0 ≤ N → NoHitDelta D A B K hD hA hB 0 N → N ≤ Nmax | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `uMinOf` は `NmaxSpec` を満たす。 | |
| 内容: `uMinOf` の可解性と最小性(`u < uMinOf` は不可解)から最大性を導く。 | |
| 証明: 反証法で示す。 | |
| 役割: 「最小可解点 = 最大安全長」を形式的に確立する中心定理。 | |
| -/ | |
| theorem uMinOf_is_NmaxSpec | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| NmaxSpec D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := by | |
| have huMinSol : SolU D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := by | |
| exact uMinOf_mem (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| rcases huMinSol with ⟨huMin0, huMinDelta⟩ | |
| refine ⟨huMin0, ?_, ?_⟩ | |
| · intro u hu0 huLt huDelta | |
| have hle : uMinOf D A B K hD hA hB hex ≤ u := by | |
| exact uMinOf_le_of_sol (D := D) (A := A) (B := B) (K := K) hD hA hB hex ⟨hu0, huDelta⟩ | |
| exact (not_lt_of_ge hle) huLt | |
| · intro N hN0 hNoHit | |
| by_contra hNle | |
| have huMinLtN : uMinOf D A B K hD hA hB hex < N := lt_of_not_ge hNle | |
| exact (hNoHit (uMinOf D A B K hD hA hB hex) huMin0 huMinLtN) huMinDelta | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `NmaxSpec` を満たす値は一意。 | |
| 内容: 2つの候補の最大性を相互適用して双方の `≤` を示し、反対称性で結ぶ。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 仕様を満たす探索結果が `uMinOf` と一致する根拠を与える。 | |
| -/ | |
| lemma NmaxSpec_unique | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| {N1 N2 : Int} | |
| (h1 : NmaxSpec D A B K hD hA hB N1) | |
| (h2 : NmaxSpec D A B K hD hA hB N2) : | |
| N1 = N2 := by | |
| rcases h1 with ⟨hN10, hNo1, hMax1⟩ | |
| rcases h2 with ⟨hN20, hNo2, hMax2⟩ | |
| have h12 : N1 ≤ N2 := hMax2 N1 hN10 hNo1 | |
| have h21 : N2 ≤ N1 := hMax1 N2 hN20 hNo2 | |
| exact le_antisymm h12 h21 | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `NmaxSpec` を返す二分探索結果 `Nmax` は `uMinOf` と一致し、`xMin = D*Nmax`。 | |
| 内容: `uMinOf_is_NmaxSpec` と `NmaxSpec_unique` で `Nmax = uMinOf` を示し、`xMin_eq_D_mul_uMinOf` で戻す。 | |
| 証明: 式変形で示す。 | |
| 役割: 探索アルゴリズム仕様から最終解の正しさを得る接続定理。 | |
| -/ | |
| theorem binary_search_correct_of_NmaxSpec | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| {Nmax : Int} | |
| (hNmax : NmaxSpec D A B K hD hA hB Nmax) : | |
| uMinOf D A B K hD hA hB hex = Nmax ∧ | |
| xMin D A B K hD hA hB = D * Nmax := by | |
| have huSpec : NmaxSpec D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := by | |
| exact uMinOf_is_NmaxSpec (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| have hEq : Nmax = uMinOf D A B K hD hA hB hex := by | |
| exact NmaxSpec_unique (D := D) (A := A) (B := B) (K := K) hD hA hB hNmax huSpec | |
| refine ⟨hEq.symm, ?_⟩ | |
| calc | |
| xMin D A B K hD hA hB = D * uMinOf D A B K hD hA hB hex := by | |
| exact xMin_eq_D_mul_uMinOf (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| _ = D * Nmax := by rw [hEq] | |
| /-- | |
| 入力/前提: hA : 0 < A。 | |
| 主張: `fBinary` を平行移動した `MWF.obj` 形に等式変換できる。 | |
| 内容: `u = (u-L)+L` で商の中身を再配置し、`fBinary = B*L + obj(..., u-L)` を示す。 | |
| 証明: 式変形で示す。 | |
| 役割: 区間最大 `F(L,R)` を `MWF.mwf` 計算へ接続する前処理補題。 | |
| -/ | |
| lemma fBinary_eq_shift_obj | |
| (hA : 0 < A) : | |
| fBinary D A B u = | |
| B * L + MWF.obj B (-(Mof D A B)) D (D * L) A (u - L) hA := by | |
| unfold fBinary | |
| have hdiv : (D * u) / A = (D * (u - L) + D * L) / A := by | |
| refine congrArg (fun t : Int => t / A) ?_ | |
| ring | |
| rw [hdiv] | |
| simp only [obj, zfloorDiv, neg_mul] | |
| ring | |
| /-- | |
| 入力/前提: hA : 0 < A、_hL0 : 0 ≤ L、hLR : L < R。 | |
| 主張: `NoHitBK D A B K L R` と `B*L + MWF.mwf(...) ≤ B*K` は同値。 | |
| 内容: `fBinary_eq_shift_obj` と `obj ≤ mwf`(および Finset 最大値評価)で両方向を示す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 区間判定を `mwf` の1回評価へ落とす実装接続の主補題。 | |
| -/ | |
| lemma NoHitBK_iff_mwf_le | |
| (hA : 0 < A) | |
| (_hL0 : 0 ≤ L) | |
| (hLR : L < R) : | |
| NoHitBK D A B K L R ↔ | |
| B * L | |
| + MWF.mwf (R - L) A B (-(Mof D A B)) D (D * L) (sub_pos.mpr hLR) hA | |
| ≤ B * K := by | |
| let N0 : Int := R - L | |
| have hN0 : 0 < N0 := by | |
| exact sub_pos.mpr hLR | |
| constructor | |
| · intro hNo | |
| have hMwfLe : MWF.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA ≤ B * K - B * L := by | |
| classical | |
| let s : Finset Int := MWF.img N0 A B (-(Mof D A B)) D (D * L) hN0 hA | |
| have hsNe : s.Nonempty := by | |
| simpa only [s, img.eq_1, obj, zfloorDiv, neg_mul, dom, Finset.image_nonempty, | |
| Finset.nonempty_Icc, Int.sub_nonneg, img] using | |
| (MWF.img_nonempty (N := N0) (M := A) (A := B) (B := -(Mof D A B)) (C := D) (D := D * L) | |
| hN0 hA) | |
| change s.max' hsNe ≤ B * K - B * L | |
| refine Finset.max'_le (s := s) (H := hsNe) (x := B * K - B * L) ?_ | |
| intro y hy | |
| have hy' : y ∈ MWF.img N0 A B (-(Mof D A B)) D (D * L) hN0 hA := by | |
| simpa only [s, img, obj, zfloorDiv, neg_mul, dom, Finset.mem_image, Finset.mem_Icc, | |
| Order.le_sub_one_iff, img.eq_1] using hy | |
| rcases Finset.mem_image.mp hy' with ⟨x, hx, rfl⟩ | |
| have hxI : x ∈ Finset.Icc (0 : Int) (N0 - 1) := by | |
| simpa only [Finset.mem_Icc, Order.le_sub_one_iff, dom] using hx | |
| rcases Finset.mem_Icc.mp hxI with ⟨hx0, hxN1⟩ | |
| have hxLt : x < N0 := by omega | |
| have hLu : L ≤ L + x := by omega | |
| have huR : L + x < R := by | |
| have : x < R - L := by simpa only using hxLt | |
| omega | |
| have hfx : fBinary D A B (L + x) ≤ B * K := hNo (L + x) hLu huR | |
| have hShift : | |
| fBinary D A B (L + x) = | |
| B * L + MWF.obj B (-(Mof D A B)) D (D * L) A x hA := by | |
| have hTmp := | |
| fBinary_eq_shift_obj | |
| (D := D) (A := A) (B := B) (L := L) (u := L + x) hA | |
| have hCancel : L + x - L = x := by ring | |
| simpa only [obj, zfloorDiv, neg_mul, hCancel] using hTmp | |
| have hSum : | |
| B * L + MWF.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K := by | |
| simpa only [obj, zfloorDiv, neg_mul, hShift] using hfx | |
| have hObj : | |
| MWF.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K - B * L := by | |
| exact | |
| (le_sub_iff_add_le).2 (by | |
| simpa only [obj, zfloorDiv, add_comm, neg_mul] using hSum) | |
| exact hObj | |
| have hSum : | |
| B * L + MWF.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA ≤ B * K := by | |
| have hTmp : | |
| MWF.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA + B * L ≤ B * K := by | |
| exact (le_sub_iff_add_le).1 hMwfLe | |
| simpa only [mwf, img, obj, zfloorDiv, add_comm, neg_mul, dom, ge_iff_le] using hTmp | |
| simpa only [mwf, img, obj, zfloorDiv, neg_mul, dom, ge_iff_le] using hSum | |
| · intro hMwf u hLu huR | |
| let x : Int := u - L | |
| have hx0 : 0 ≤ x := by | |
| exact sub_nonneg.mpr hLu | |
| have hxLt : x < N0 := by | |
| dsimp only [x, N0] | |
| exact sub_lt_sub_right huR L | |
| have hxN1 : x ≤ N0 - 1 := by omega | |
| have hxDom : x ∈ MWF.dom N0 hN0 := by | |
| change x ∈ Finset.Icc (0 : Int) (N0 - 1) | |
| exact Finset.mem_Icc.mpr ⟨hx0, hxN1⟩ | |
| have hObjLeMwf : | |
| MWF.obj B (-(Mof D A B)) D (D * L) A x hA | |
| ≤ MWF.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA := by | |
| exact | |
| MWF.obj_le_mwf_of_mem | |
| (N := N0) (M := A) (A := B) (B := -(Mof D A B)) (C := D) (D := D * L) hN0 hA | |
| (y := x) hxDom | |
| have hMwfLe : MWF.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA ≤ B * K - B * L := by | |
| have hMwf' : | |
| B * L + MWF.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA ≤ B * K := by | |
| simpa only [mwf, img, obj, zfloorDiv, neg_mul, dom] using hMwf | |
| exact | |
| (le_sub_iff_add_le).2 (by | |
| simpa only [mwf, img, obj, zfloorDiv, add_comm, neg_mul, dom] using hMwf') | |
| have hObj : | |
| MWF.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K - B * L := | |
| le_trans hObjLeMwf hMwfLe | |
| have hShift : | |
| fBinary D A B u = B * L + MWF.obj B (-(Mof D A B)) D (D * L) A x hA := by | |
| simpa only [obj, zfloorDiv, neg_mul] using | |
| (fBinary_eq_shift_obj (D := D) (A := A) (B := B) (L := L) (u := u) hA) | |
| have hSum : B * L + MWF.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K := by | |
| have hTmp : MWF.obj B (-(Mof D A B)) D (D * L) A x hA + B * L ≤ B * K := by | |
| exact (le_sub_iff_add_le).1 hObj | |
| simpa only [obj, zfloorDiv, add_comm, neg_mul, ge_iff_le] using hTmp | |
| simpa only [hShift, obj, zfloorDiv, neg_mul, ge_iff_le] using hSum | |
| /-- | |
| 入力/前提: hA : 0 < A、_hL0 : 0 ≤ L、hLR : L < R。 | |
| 主張: `NoHitBK D A B K L R` と `MWF.mwfLr ... ≤ B*K` は同値。 | |
| 内容: `MWF.mwfLr` を `[L,R)` 上の `fBinary` 最大値として評価し、全称条件と突き合わせる。 | |
| 証明: `Finset.max'` の評価(上界化と要素評価)で示す。 | |
| 役割: `mwfLr_iter_le`(`mwfLr_iter` 判定)を `NoHitBK` に接続するために使う。 | |
| -/ | |
| lemma NoHitBK_iff_mwfLr_le | |
| (hA : 0 < A) | |
| (_hL0 : 0 ≤ L) | |
| (hLR : L < R) : | |
| NoHitBK D A B K L R ↔ | |
| MWF.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA ≤ B * K := by | |
| constructor | |
| · intro hNo | |
| unfold MWF.mwfLr | |
| dsimp only [imgLr.eq_1, obj.eq_1, zfloorDiv.eq_1, domLr.eq_1, Lean.Elab.WF.paramLet] | |
| let s : Finset Int := MWF.imgLr L R A B (-(Mof D A B)) D 0 hLR hA | |
| have hsNe : s.Nonempty := by | |
| simpa only [s, imgLr.eq_1, obj, zfloorDiv, add_zero, neg_mul, domLr, Finset.image_nonempty, | |
| Finset.nonempty_Icc, Order.le_sub_one_iff, imgLr] using | |
| (MWF.imgLr_nonempty (L := L) (R := R) (M := A) (A := B) (B := -(Mof D A B)) (C := D) (D := | |
| 0) hLR hA) | |
| change s.max' hsNe ≤ B * K | |
| refine Finset.max'_le (s := s) (H := hsNe) (x := B * K) ?_ | |
| intro y hy | |
| have hy' : y ∈ MWF.imgLr L R A B (-(Mof D A B)) D 0 hLR hA := by | |
| simpa only [s, imgLr, obj, zfloorDiv, add_zero, neg_mul, domLr, Finset.mem_image, | |
| Finset.mem_Icc, Order.le_sub_one_iff, imgLr.eq_1] using hy | |
| rcases Finset.mem_image.mp hy' with ⟨u, hu, rfl⟩ | |
| have huI : u ∈ Finset.Icc L (R - 1) := by | |
| simpa only [Finset.mem_Icc, Order.le_sub_one_iff, domLr] using hu | |
| rcases Finset.mem_Icc.mp huI with ⟨hLu, huR1⟩ | |
| have huR : u < R := by omega | |
| have hObj : | |
| MWF.obj B (-(Mof D A B)) D 0 A u hA = fBinary D A B u := by | |
| calc | |
| MWF.obj B (-(Mof D A B)) D 0 A u hA | |
| = B * u + (-(Mof D A B)) * ((D * u + 0) / A) := by | |
| simp only [obj, zfloorDiv, add_zero, neg_mul] | |
| _ = B * u - (Mof D A B) * ((D * u) / A) := by ring_nf | |
| _ = fBinary D A B u := by | |
| simp only [fBinary] | |
| have hNoU : fBinary D A B u ≤ B * K := hNo u hLu huR | |
| rw [hObj] | |
| exact hNoU | |
| · intro hMwf u hLu huR | |
| have huR1 : u ≤ R - 1 := by omega | |
| have huDom : u ∈ MWF.domLr L R hLR := by | |
| change u ∈ Finset.Icc L (R - 1) | |
| exact Finset.mem_Icc.mpr ⟨hLu, huR1⟩ | |
| have hObjLe : | |
| MWF.obj B (-(Mof D A B)) D 0 A u hA | |
| ≤ MWF.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA := by | |
| unfold MWF.mwfLr | |
| dsimp only [obj, zfloorDiv, imgLr, domLr, Lean.Elab.WF.paramLet] | |
| exact | |
| Finset.le_max' (s := MWF.imgLr L R A B (-(Mof D A B)) D 0 hLR hA) | |
| (x := MWF.obj B (-(Mof D A B)) D 0 A u hA) | |
| (Finset.mem_image.mpr ⟨u, huDom, rfl⟩) | |
| have hObj : | |
| MWF.obj B (-(Mof D A B)) D 0 A u hA = fBinary D A B u := by | |
| calc | |
| MWF.obj B (-(Mof D A B)) D 0 A u hA | |
| = B * u + (-(Mof D A B)) * ((D * u + 0) / A) := by | |
| simp only [obj, zfloorDiv, add_zero, neg_mul] | |
| _ = B * u - (Mof D A B) * ((D * u) / A) := by ring_nf | |
| _ = fBinary D A B u := by | |
| simp only [fBinary] | |
| have hObjLeBK : MWF.obj B (-(Mof D A B)) D 0 A u hA ≤ B * K := le_trans hObjLe hMwf | |
| rw [hObj] at hObjLeBK | |
| exact hObjLeBK | |
| /-- | |
| 入力/前提: hD : 0 < D。 | |
| 主張: `D > 0` の下で `D*u < X ↔ u < (X + D - 1) / D`。 | |
| 内容: `u+1` 形に変換して `Int.le_ediv_iff_mul_le` を往復する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `x` 側閾値比較を `u` 側の天井除算比較へ変換する。 | |
| -/ | |
| lemma mul_lt_X_iff_lt_ceilDiv | |
| (hD : 0 < D) : | |
| D * u < X ↔ u < (X + D - 1) / D := by | |
| constructor | |
| · intro hMul | |
| have hDU1 : D * u + 1 ≤ X := (Int.add_one_le_iff).2 hMul | |
| have hMul' : (u + 1) * D ≤ X + D - 1 := by | |
| have hTmp : D * u + 1 + (D - 1) ≤ X + (D - 1) := by | |
| simpa only [add_assoc, add_sub_cancel, add_comm] using add_le_add_right hDU1 (D - 1) | |
| calc | |
| (u + 1) * D = D * u + 1 + (D - 1) := by ring | |
| _ ≤ X + (D - 1) := hTmp | |
| _ = X + D - 1 := by ring | |
| have hU1 : u + 1 ≤ (X + D - 1) / D := (Int.le_ediv_iff_mul_le hD).2 hMul' | |
| exact (Int.lt_iff_add_one_le).2 hU1 | |
| · intro hLt | |
| have hU1 : u + 1 ≤ (X + D - 1) / D := (Int.lt_iff_add_one_le).1 hLt | |
| have hMul' : (u + 1) * D ≤ X + D - 1 := (Int.le_ediv_iff_mul_le hD).1 hU1 | |
| have hDU1 : D * u + 1 ≤ X := by | |
| have hSub : (u + 1) * D - (D - 1) ≤ X + D - 1 - (D - 1) := sub_le_sub_right hMul' (D - 1) | |
| calc | |
| D * u + 1 = (u + 1) * D - (D - 1) := by ring | |
| _ ≤ X + D - 1 - (D - 1) := hSub | |
| _ = X := by ring | |
| exact (Int.add_one_le_iff).1 hDU1 | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `¬ NoHitDelta ... L R` は区間内のヒット点存在と同値。 | |
| 内容: `NoHitDelta` の全称否定を `simp` で存在形へ展開する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 不成立判定を具体的な証人 `u` の存在として扱う補助補題。 | |
| -/ | |
| lemma not_NoHitDelta_iff_exists | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) : | |
| ¬ NoHitDelta D A B K hD hA hB L R ↔ | |
| ∃ u : Int, L ≤ u ∧ u < R ∧ K < Delta D A B (D * u) hD hA hB := by | |
| classical | |
| simp [NoHitDelta, not_lt, not_forall, not_le] | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 解があるとき `¬ NoHitDelta ... 0 N ↔ uMinOf < N`。 | |
| 内容: `→` は区間内可解点から `uMinOf ≤ u < N`、`←` は `uMinOf` 自身を証人に使う。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 区間判定と最小解の位置比較を同一視する。 | |
| -/ | |
| lemma not_NoHitDelta_zero_iff_uMin_lt | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| ¬ NoHitDelta D A B K hD hA hB 0 N ↔ | |
| uMinOf D A B K hD hA hB hex < N := by | |
| constructor | |
| · intro hNot | |
| rcases | |
| (not_NoHitDelta_iff_exists | |
| (D := D) (A := A) (B := B) (K := K) (L := 0) (R := N) hD hA hB).1 hNot with | |
| ⟨u, hu0, huN, huDelta⟩ | |
| have hLe : | |
| uMinOf D A B K hD hA hB hex ≤ u := by | |
| exact uMinOf_le_of_sol (D := D) (A := A) (B := B) (K := K) hD hA hB hex ⟨hu0, huDelta⟩ | |
| exact lt_of_le_of_lt hLe huN | |
| · intro huLt hNo | |
| rcases uMinOf_mem (D := D) (A := A) (B := B) (K := K) hD hA hB hex with ⟨hu0, huDelta⟩ | |
| exact (hNo (uMinOf D A B K hD hA hB hex) hu0 huLt) huDelta | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `Nceil = (X + D - 1)/D` として `xMin < X ↔ ¬ NoHitDelta ... 0 Nceil`。 | |
| 内容: `xMin = D*uMinOf`、`mul_lt_X_iff_lt_ceilDiv`、`not_NoHitDelta_zero_iff_uMin_lt` を連結する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `x_min < X` を `NoHitDelta` の1回評価に帰着する判定定理。 | |
| -/ | |
| theorem xMin_lt_X_iff_not_NoHitDelta | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| (_hX : 0 ≤ X) : | |
| let Nceil : Int := (X + D - 1) / D | |
| xMin D A B K hD hA hB < X ↔ | |
| ¬ NoHitDelta D A B K hD hA hB 0 Nceil := by | |
| dsimp only [Lean.Elab.WF.paramLet] | |
| have hxEq : | |
| xMin D A B K hD hA hB = D * uMinOf D A B K hD hA hB hex := by | |
| exact xMin_eq_D_mul_uMinOf (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| have hNoHit : | |
| ¬ NoHitDelta D A B K hD hA hB 0 ((X + D - 1) / D) ↔ | |
| uMinOf D A B K hD hA hB hex < (X + D - 1) / D := by | |
| exact | |
| not_NoHitDelta_zero_iff_uMin_lt | |
| (D := D) (A := A) (B := B) (K := K) (N := (X + D - 1) / D) hD hA hB hex | |
| constructor | |
| · intro hxLt | |
| have hMul : D * uMinOf D A B K hD hA hB hex < X := by | |
| simpa only [hxEq] using hxLt | |
| have huLt : uMinOf D A B K hD hA hB hex < (X + D - 1) / D := by | |
| exact | |
| (mul_lt_X_iff_lt_ceilDiv | |
| (D := D) (X := X) (u := uMinOf D A B K hD hA hB hex) hD).1 hMul | |
| exact hNoHit.mpr huLt | |
| · intro hNot | |
| have huLt : uMinOf D A B K hD hA hB hex < (X + D - 1) / D := hNoHit.mp hNot | |
| have hMul : D * uMinOf D A B K hD hA hB hex < X := by | |
| exact | |
| (mul_lt_X_iff_lt_ceilDiv | |
| (D := D) (X := X) (u := uMinOf D A B K hD hA hB hex) hD).2 huLt | |
| simpa only [hxEq, gt_iff_lt] using hMul | |
| end BinarySearchMinSketch | |
| section Executable | |
| open MWF | |
| /-- | |
| 目的: 除数 `10^19` に対する標準の商・剰余ペアを定義する。 | |
| 定義: `divmod_d19 x := (x / 10^19, x % 10^19)`。 | |
| 入力/前提: `x : Int`。 | |
| 出力: 型 `Int × Int` の値 `(x / 10^19, x % 10^19)` を返す。 | |
| 役割: `divmod_d19_125bit` / `divmod_d19_127bit` / `divmod_d19_128bit` | |
| の正しさ定理における比較対象(仕様)として使う。 | |
| -/ | |
| def divmod_d19 (x : Int) : Int × Int := | |
| (x / (10 ^ (19 : Nat)), x % (10 ^ (19 : Nat))) | |
| /-- | |
| 目的: `D = 10^19` に対する近似商・剰余 `(q, r)` を 1 回補正で計算する。 | |
| 定義: `A = 2^63`, `B = 2^64`, `M = ⌊AB/D⌋`, | |
| `q = ⌊⌊x/A⌋ * M / B⌋`, `r = x - q*D` とし、 | |
| `r ≥ D` なら `(q+1, r-D)`、それ以外は `(q, r)` を返す。 | |
| 入力/前提: `x : Int`。想定利用域は `0 ≤ x < xBound_d19_125bit`。 | |
| 出力: 型 `Int × Int` の値 `(q, r)` を返す。 | |
| 役割: `divmod(x, 10^19)` の 125bit 版補助関数。 | |
| 正しさは `divmod_d19_125bit_correct_on_range` で与える。 | |
| -/ | |
| def divmod_d19_125bit (x : Int) : Int × Int := | |
| let D : Int := 10 ^ (19 : Nat) | |
| let A : Int := 2 ^ (63 : Nat) | |
| let B : Int := 2 ^ (64 : Nat) | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| if D ≤ r then | |
| (q + 1, r - D) | |
| else | |
| (q, r) | |
| /-- | |
| 目的: `D = 10^19` に対し、`2^127` 近似商から最大 2 回補正で `(q, r)` を返す。 | |
| 定義: `A = 2^63`, `B = 2^64`, `M = ⌊AB/D⌋`, | |
| `q = ⌊⌊x/A⌋ * M / B⌋`, `r = x - q*D` として、 | |
| `r ≥ 2D` なら `(q+2, r-2D)`、`r ≥ D` なら `(q+1, r-D)`、 | |
| それ以外は `(q, r)` を返す。 | |
| 入力/前提: `x : Int`。想定利用域は `0 ≤ x < 2^127 < xBound_d19_127bit`。 | |
| 出力: 型 `Int × Int` の値 `(q, r)` を返す。 | |
| 役割: `divmod(x, 10^19)` を 127bit 近似商+最大2回補正で実行する補助関数。 | |
| 正しさは `divmod_d19_127bit_correct_on_range` で与える。 | |
| -/ | |
| def divmod_d19_127bit (x : Int) : Int × Int := | |
| let D : Int := 10 ^ (19 : Nat) | |
| let A : Int := 2 ^ (63 : Nat) | |
| let B : Int := 2 ^ (64 : Nat) | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| if D * 2 ≤ r then | |
| (q + 2, r - D * 2) | |
| else if D ≤ r then | |
| (q + 1, r - D) | |
| else | |
| (q, r) | |
| /-- | |
| 目的: `D = 10^19` に対し、`2^128` 近似商から最大 3 回補正で `(q, r)` を返す。 | |
| 定義: `A = 2^64`, `B = 2^64`, `M = ⌊AB/D⌋`, | |
| `q = ⌊⌊x/A⌋ * M / B⌋`, `r = x - q*D` として、 | |
| `r ≥ 3D` なら `(q+3, r-3D)`、`r ≥ 2D` なら `(q+2, r-2D)`、 | |
| `r ≥ D` なら `(q+1, r-D)`、それ以外は `(q, r)` を返す。 | |
| 入力/前提: `x : Int`。想定利用域は `0 ≤ x < 2^128 < xBound_d19_128bit`。 | |
| 出力: 型 `Int × Int` の値 `(q, r)` を返す。 | |
| 役割: `divmod(x, 10^19)` を 128bit 近似商+最大3回補正で実行する補助関数。 | |
| 正しさは `divmod_d19_128bit_correct_on_range` で与える。 | |
| -/ | |
| def divmod_d19_128bit (x : Int) : Int × Int := | |
| let D : Int := 10 ^ (19 : Nat) | |
| let A : Int := 2 ^ (64 : Nat) | |
| let B : Int := 2 ^ (64 : Nat) | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| if D * 3 ≤ r then | |
| (q + 3, r - D * 3) | |
| else if D * 2 ≤ r then | |
| (q + 2, r - D * 2) | |
| else if D ≤ r then | |
| (q + 1, r - D) | |
| else | |
| (q, r) | |
| /-- | |
| 目的: 区間最大値判定 `max_{l≤u<r} fBinary(u) ≤ t` を実行可能な `Bool` として与える。 | |
| 定義: `l<r` と `0<m` が満たされるとき `MWF.mwfLr_iter` を評価し、`≤ t` を `decide` で返す。 | |
| 入力/前提: t l r m a b c d : Int。 | |
| 出力: 型 `Bool` の値を返す。 | |
| 役割: 二分探索の分岐判定(`lo` 側が安全か)に用いる。 | |
| -/ | |
| def mwfLr_iter_le (t l r m a b c d : Int) : Bool := | |
| if hLR : l < r then | |
| if hM : 0 < m then | |
| decide (MWF.mwfLr_iter l r m a b c d hLR hM ≤ t) | |
| else | |
| true | |
| else | |
| true | |
| /-- | |
| 目的: `u` 上の探索本体を実行可能に定義する。 | |
| 定義: `fuel` 回を上限に区間 `[lo,hi)` を二分し、左半分の安全性で分岐して最初の unsafe 点を返す。 | |
| 入力/前提: fuel bk lo hi A B M D : Int、hA : 0 < A。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `compute_u_binary` の反復本体。 | |
| -/ | |
| def compute_u_binary_aux | |
| (fuel : Nat) (bk lo hi A B M D : Int) (hA : 0 < A) : Int := | |
| match fuel with | |
| | 0 => lo | |
| | fuel + 1 => | |
| if _hGap : lo + 1 < hi then | |
| let mid := (lo + hi) / 2 | |
| if mwfLr_iter_le bk lo mid A B (-M) D 0 then | |
| compute_u_binary_aux fuel bk mid hi A B M D hA | |
| else | |
| compute_u_binary_aux fuel bk lo mid A B M D hA | |
| else | |
| lo | |
| /-- | |
| 目的: `u` 側探索を実行する。 | |
| 定義: 始点 `lo` と上端 `hi` の区間を `compute_u_binary_aux` で二分探索し、最初の unsafe 点を返す。 | |
| 入力/前提: bk lo hi A B M D : Int、hA : 0 < A。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `compute_xmin` から直接使う `u` 探索インターフェース。 | |
| -/ | |
| def compute_u_binary (bk lo hi A B M D : Int) (hA : 0 < A) : Int := | |
| compute_u_binary_aux (Int.toNat (hi - lo + 1)) bk lo hi A B M D hA | |
| /-- | |
| 目的: 問題 `xMin(D,A,B,K)` の計算版を定義する。 | |
| 定義: `R=(AB)%D` の分岐で探索区間 `[lo,hi)` を作り、区間判定 `mwfLr_iter_le` を使う二分探索で `u_min` | |
| を求め、`x_min = D * u_min` を返す。解が無い場合(`R=0` かつ `D*K+gcd(D,A)≥A`)は `-1`。 | |
| 入力/前提: D A B K : Int(実装上は `D>0, A>0, B>0, K≥0` を想定)。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 後続の正当性証明で結び付ける実行可能アルゴリズム本体。 | |
| -/ | |
| def compute_xMin (D A B K : Int) : Int := | |
| if _hD : 0 < D then | |
| if hA : 0 < A then | |
| if _hB : 0 < B then | |
| if _hK : 0 ≤ K then | |
| let g : Int := gcdDA D A | |
| let bk : Int := B * K | |
| let M : Int := Mof D A B | |
| let R : Int := Rof D A B | |
| if _hR0 : R = 0 then | |
| if _hNo : A ≤ D * K + g then | |
| -1 | |
| else | |
| let lo : Int := K + 1 | |
| let hi : Int := A / g | |
| D * compute_u_binary bk lo hi A B M D hA | |
| else | |
| let lo : Int := K + 1 | |
| let hi : Int := (A * B * K) / R + 2 | |
| D * compute_u_binary bk lo hi A B M D hA | |
| else | |
| -1 | |
| else | |
| -1 | |
| else | |
| -1 | |
| else | |
| -1 | |
| end Executable | |
| -- #eval compute_xMin 1 1 1 0 -- 例: D=1, A=1, B=1, K=0 のときの x_min を計算 | |
| -- #eval compute_xMin 998244353 1000000000 1000000000 2 | |
| -- #eval compute_xMin 420196140727489673 679891637638612258 999999999999999989 7 | |
| -- #eval compute_xMin 10000000000000000000 18446744073709551616 18446744073709551616 2 | |
| -- #eval compute_xMin 10000000000000000000 18446744073709551616 18446744073709551616 3 | |
| section ComputeCorrectness | |
| variable {D A B K : Int} | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hL0 : 0 ≤ L`。 | |
| 主張: 判定 `mwfLr_iter_le` は `NoHitBK` と同値。 | |
| 内容: `L < R` の場合は `MWF.mwfLr_iter_collect` と `NoHitBK_iff_mwfLr_le` に還元し、 | |
| `L ≥ R` の場合は空区間で自明。 | |
| 証明: 場合分けと `simp` で示す。 | |
| 役割: 実装側 Bool 判定を論理側述語へ持ち上げる接続補題。 | |
| -/ | |
| lemma mwfLr_iter_le_iff_NoHitBK | |
| {L R : Int} | |
| (hA : 0 < A) | |
| (hL0 : 0 ≤ L) : | |
| mwfLr_iter_le (B * K) L R A B (-(Mof D A B)) D 0 = true ↔ | |
| NoHitBK D A B K L R := by | |
| by_cases hLR : L < R | |
| · have hCollect : | |
| MWF.mwfLr_iter L R A B (-(Mof D A B)) D 0 hLR hA | |
| = MWF.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA := by | |
| exact MWF.mwfLr_iter_collect L R A B (-(Mof D A B)) D 0 hLR hA | |
| have hNoHit : | |
| NoHitBK D A B K L R ↔ | |
| MWF.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA ≤ B * K := by | |
| exact | |
| NoHitBK_iff_mwfLr_le | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hL0 hLR | |
| have hBool : | |
| mwfLr_iter_le (B * K) L R A B (-(Mof D A B)) D 0 = true ↔ | |
| MWF.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA ≤ B * K := by | |
| simp only [mwfLr_iter_le, hLR, ↓reduceDIte, hA, hCollect, MWF.mwfLr, MWF.imgLr, MWF.obj, | |
| MWF.zfloorDiv, add_zero, neg_mul, MWF.domLr, Finset.max'_le_iff, Finset.mem_image, | |
| Finset.mem_Icc, Order.le_sub_one_iff, forall_exists_index, and_imp, decide_eq_true_eq] | |
| exact hBool.trans hNoHit.symm | |
| · have hRleL : R ≤ L := le_of_not_gt hLR | |
| have hNo : NoHitBK D A B K L R := by | |
| intro u hLu huR | |
| exfalso | |
| exact (not_lt_of_ge (le_trans hRleL hLu)) huR | |
| simp only [mwfLr_iter_le, hLR, ↓reduceDIte, hNo] | |
| /-- | |
| 入力/前提: なし(古典論理)。 | |
| 主張: `¬ NoHitBK ... L R` は区間内の unsafe 点の存在と同値。 | |
| 内容: 全称否定を存在形に展開する。 | |
| 証明: 反証法で示す。 | |
| 役割: 左半区間が unsafe な分岐で証人 `u` を取り出すために使う。 | |
| -/ | |
| lemma not_NoHitBK_iff_exists_hit | |
| {L R : Int} : | |
| ¬ NoHitBK D A B K L R ↔ | |
| ∃ u : Int, L ≤ u ∧ u < R ∧ B * K < fBinary D A B u := by | |
| classical | |
| constructor | |
| · intro hNot | |
| by_contra hNoEx | |
| apply hNot | |
| intro u hLu huR | |
| by_contra hGe | |
| exact hNoEx ⟨u, hLu, huR, lt_of_not_ge hGe⟩ | |
| · intro hEx hNo | |
| rcases hEx with ⟨u, hLu, huR, hGt⟩ | |
| exact (not_lt_of_ge (hNo u hLu huR)) hGt | |
| /-- | |
| 入力/前提: `tgt` は最小 unsafe 点(`hTgtUnsafe`, `hTgtMin`)。 | |
| 主張: 区間不変量 `lo ≤ tgt < hi` と幅上界 `hi-lo ≤ fuel` の下で | |
| `compute_u_binary_aux` は `tgt` を返す。 | |
| 内容: `lo+1<hi` なら中点 `mid` で分岐し、左半分安全なら `mid ≤ tgt`、 | |
| unsafe なら証人から `tgt < mid` を得て帰納法を適用する。 | |
| 証明: `fuel` に関する帰納法で示す。 | |
| 役割: `compute_u_binary_eq_uMinOf_of_hi` の中核補題。 | |
| -/ | |
| lemma compute_u_binary_aux_eq_tgt | |
| (hA : 0 < A) | |
| (tgt : Int) | |
| (hTgtUnsafe : B * K < fBinary D A B tgt) | |
| (hTgtMin : ∀ u : Int, 0 ≤ u → B * K < fBinary D A B u → tgt ≤ u) : | |
| ∀ fuel : Nat, ∀ lo hi : Int, | |
| 0 ≤ lo → | |
| lo ≤ tgt → | |
| tgt < hi → | |
| hi - lo ≤ (fuel : Int) → | |
| compute_u_binary_aux fuel (B * K) lo hi A B (Mof D A B) D hA = tgt := by | |
| intro fuel | |
| induction fuel with | |
| | zero => | |
| intro lo hi hlo0 hloTgt htgtHi hWidth | |
| have : False := by omega | |
| exact False.elim this | |
| | succ fuel ih => | |
| intro lo hi hlo0 hloTgt htgtHi hWidth | |
| by_cases hGap : lo + 1 < hi | |
| · set mid : Int := (lo + hi) / 2 | |
| have hTwoPos : (0 : Int) < 2 := by decide | |
| have hMidGeLo1 : lo + 1 ≤ mid := by | |
| have hMul : (lo + 1) * 2 ≤ lo + hi := by omega | |
| have hDiv : lo + 1 ≤ (lo + hi) / 2 := (Int.le_ediv_iff_mul_le hTwoPos).2 hMul | |
| simpa only [Order.add_one_le_iff, gt_iff_lt] using hDiv | |
| have hMidLtHi : mid < hi := by | |
| have hMul : lo + hi < hi * 2 := by omega | |
| have hDiv : (lo + hi) / 2 < hi := (Int.ediv_lt_iff_lt_mul hTwoPos).2 hMul | |
| simpa only [gt_iff_lt] using hDiv | |
| by_cases hSafe : | |
| mwfLr_iter_le (B * K) lo mid A B (-(Mof D A B)) D 0 = true | |
| · have hNoLeft : NoHitBK D A B K lo mid := by | |
| exact (mwfLr_iter_le_iff_NoHitBK | |
| (D := D) (A := A) (B := B) (K := K) (L := lo) (R := mid) hA hlo0).1 hSafe | |
| have hMidLeTgt : mid ≤ tgt := by | |
| by_contra hNot | |
| have hTgtLtMid : tgt < mid := lt_of_not_ge hNot | |
| have hSafeTgt : fBinary D A B tgt ≤ B * K := hNoLeft tgt hloTgt hTgtLtMid | |
| exact (not_lt_of_ge hSafeTgt) hTgtUnsafe | |
| have hMid0 : 0 ≤ mid := by omega | |
| have hWidthRight : hi - mid ≤ (fuel : Int) := by | |
| omega | |
| simpa only [compute_u_binary_aux, hGap, mid, ↓reduceDIte, hSafe, ↓reduceIte] using | |
| ih mid hi hMid0 hMidLeTgt htgtHi hWidthRight | |
| · have hNoLeft : ¬ NoHitBK D A B K lo mid := by | |
| intro hNo | |
| exact hSafe ((mwfLr_iter_le_iff_NoHitBK | |
| (D := D) (A := A) (B := B) (K := K) (L := lo) (R := mid) hA hlo0).2 hNo) | |
| have hEx : | |
| ∃ u : Int, lo ≤ u ∧ u < mid ∧ B * K < fBinary D A B u := by | |
| exact (not_NoHitBK_iff_exists_hit | |
| (D := D) (A := A) (B := B) (K := K) (L := lo) (R := mid)).1 hNoLeft | |
| rcases hEx with ⟨u, hLu, huMid, huUnsafe⟩ | |
| have hu0 : 0 ≤ u := le_trans hlo0 hLu | |
| have hTgtLtMid : tgt < mid := by | |
| exact lt_of_le_of_lt (hTgtMin u hu0 huUnsafe) huMid | |
| have hWidthLeft : mid - lo ≤ (fuel : Int) := by | |
| omega | |
| simpa only [compute_u_binary_aux, hGap, mid, ↓reduceDIte, hSafe, Bool.false_eq_true, | |
| ↓reduceIte] using ih lo mid hlo0 hloTgt hTgtLtMid hWidthLeft | |
| · have hEq : tgt = lo := by | |
| have hHiLe : hi ≤ lo + 1 := le_of_not_gt hGap | |
| omega | |
| simp only [compute_u_binary_aux, hGap, ↓reduceDIte, hEq] | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`。 | |
| 主張: `hi` が `uMinOf` の上界なら、実装側 `compute_u_binary` は `uMinOf` を返す。 | |
| 内容: 二分探索 `compute_u_binary_aux` について、左半区間安全判定と最小可解点の性質を接続する。 | |
| 証明: `uMinOf` の unsafe 性と最小性を `compute_u_binary_aux_eq_tgt` に渡し、 | |
| 初期区間 `[K+1, hi)` と fuel 上界 `hi-(K+1) ≤ toNat(hi-(K+1)+1)` を与えて示す。 | |
| 役割: `R=0` / `R≠0` の両分岐で使う共通接続補題。 | |
| -/ | |
| lemma compute_u_binary_eq_uMinOf_of_hi | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) : | |
| ∀ (hex : HasUSolution D A B K hD hA hB) | |
| (hi : Int), | |
| K + 1 ≤ uMinOf D A B K hD hA hB hex → | |
| uMinOf D A B K hD hA hB hex < hi → | |
| compute_u_binary (B * K) (K + 1) hi A B (Mof D A B) D hA | |
| = uMinOf D A B K hD hA hB hex := by | |
| intro hex hi hlo htgtHi | |
| let tgt : Int := uMinOf D A B K hD hA hB hex | |
| have huMin : SolU D A B K hD hA hB tgt := by | |
| simpa only using (uMinOf_mem (D := D) (A := A) (B := B) (K := K) hD hA hB hex) | |
| have hTgtUnsafe : B * K < fBinary D A B tgt := by | |
| exact | |
| (lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := tgt) hD hA hB huMin.1 hK).1 huMin.2 | |
| have hTgtMin : ∀ u : Int, 0 ≤ u → B * K < fBinary D A B u → tgt ≤ u := by | |
| intro u hu0 huUnsafe | |
| have huDelta : K < Delta D A B (D * u) hD hA hB := by | |
| exact | |
| (lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := u) hD hA hB hu0 hK).2 huUnsafe | |
| have hle : | |
| uMinOf D A B K hD hA hB hex ≤ u := by | |
| exact | |
| uMinOf_le_of_sol | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex ⟨hu0, huDelta⟩ | |
| simpa only [ge_iff_le] using hle | |
| have hlo0 : 0 ≤ K + 1 := by omega | |
| have hlo' : K + 1 ≤ tgt := by simpa only [Order.add_one_le_iff] using hlo | |
| have htgtHi' : tgt < hi := by simpa only using htgtHi | |
| have hWidthNonneg : 0 ≤ hi - (K + 1) := by omega | |
| have hWidthCast : | |
| (Int.toNat (hi - (K + 1) + 1) : Int) = hi - (K + 1) + 1 := by | |
| exact Int.toNat_of_nonneg (by omega) | |
| have hWidth : | |
| hi - (K + 1) ≤ (Int.toNat (hi - (K + 1) + 1) : Int) := by | |
| calc | |
| hi - (K + 1) ≤ hi - (K + 1) + 1 := by omega | |
| _ = (Int.toNat (hi - (K + 1) + 1) : Int) := by | |
| symm | |
| exact hWidthCast | |
| have hAux : | |
| compute_u_binary_aux (Int.toNat (hi - (K + 1) + 1)) (B * K) (K + 1) hi A B (Mof D A B) D hA | |
| = tgt := by | |
| exact | |
| compute_u_binary_aux_eq_tgt | |
| (D := D) (A := A) (B := B) (K := K) | |
| hA tgt hTgtUnsafe hTgtMin | |
| (Int.toNat (hi - (K + 1) + 1)) (K + 1) hi | |
| hlo0 hlo' htgtHi' hWidth | |
| simpa only [compute_u_binary] using hAux | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`。 | |
| 主張: `R=0` かつ可解な場合、実装側 `compute_u_binary` が `uMinOf` と一致する(`x=D*u` 形)。 | |
| 内容: `R=0` 同値条件から `D*K+gcd(D,A)<A` を得て、 | |
| `uMin_lower_bound`・`uMin_lt_A_div_g_of_R_eq_zero` で探索範囲を閉じる。 | |
| 証明: `compute_u_binary_eq_uMinOf_of_hi` を `hi = A/g` に適用する。 | |
| 役割: `compute_xMin_eq_xMin` の `R=0` 可解分岐を閉じる。 | |
| -/ | |
| lemma hbinR0 | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) : | |
| ∀ (hex : HasUSolution D A B K hD hA hB), | |
| Rof D A B = 0 → | |
| D * compute_u_binary (B * K) (K + 1) (A / gcdDA D A) A B (Mof D A B) D hA | |
| = D * uMinOf D A B K hD hA hB hex := by | |
| intro hex hR0 | |
| have hiff : | |
| HasUSolution D A B K hD hA hB ↔ D * K + gcdDA D A < A := by | |
| exact | |
| exists_u_iff_DK_add_g_lt_A_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 | |
| have hcond : D * K + gcdDA D A < A := hiff.mp hex | |
| have hlo : (K + 1 : Int) ≤ uMinOf D A B K hD hA hB hex := by | |
| exact uMin_lower_bound (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| have htgtHi : uMinOf D A B K hD hA hB hex < A / gcdDA D A := by | |
| exact | |
| uMin_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond hex | |
| have hEq : | |
| compute_u_binary (B * K) (K + 1) (A / gcdDA D A) A B (Mof D A B) D hA | |
| = uMinOf D A B K hD hA hB hex := by | |
| exact | |
| compute_u_binary_eq_uMinOf_of_hi | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK | |
| hex (A / gcdDA D A) hlo htgtHi | |
| simp only [hEq] | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`。 | |
| 主張: `R≠0` かつ可解な場合、実装側 `compute_u_binary` が `uMinOf` と一致する(`x=D*u` 形)。 | |
| 内容: `uMin_lower_bound` と `uMin_lt_floor_ABK_div_R_plus_two_of_R_ne_zero` で探索範囲を閉じる。 | |
| 証明: `compute_u_binary_eq_uMinOf_of_hi` を `hi = floor(ABK/R)+2` に適用する。 | |
| 役割: `compute_xMin_eq_xMin` の `R≠0` 分岐を閉じる。 | |
| -/ | |
| lemma hbinRnz | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) : | |
| ∀ (hex : HasUSolution D A B K hD hA hB), | |
| Rof D A B ≠ 0 → | |
| let lo : Int := K + 1 | |
| let hi : Int := (A * B * K) / (Rof D A B) + 2 | |
| D * compute_u_binary (B * K) lo hi A B (Mof D A B) D hA | |
| = D * uMinOf D A B K hD hA hB hex := by | |
| intro hex hRnz | |
| dsimp only [Lean.Elab.WF.paramLet] | |
| have hlo : (K + 1 : Int) ≤ uMinOf D A B K hD hA hB hex := by | |
| exact uMin_lower_bound (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| have htgtHi : | |
| uMinOf D A B K hD hA hB hex < (A * B * K) / (Rof D A B) + 2 := by | |
| exact | |
| uMin_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz hex | |
| have hEq : | |
| compute_u_binary (B * K) (K + 1) ((A * B * K) / (Rof D A B) + 2) A B (Mof D A B) D hA | |
| = uMinOf D A B K hD hA hB hex := by | |
| exact | |
| compute_u_binary_eq_uMinOf_of_hi | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK | |
| hex ((A * B * K) / (Rof D A B) + 2) hlo htgtHi | |
| simp only [hEq] | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`。 | |
| 主張: 実装 `compute_xMin` は仕様定義 `xMin` と一致する。 | |
| 内容: `Rof D A B = 0` / `Rof D A B ≠ 0` で分岐し、 | |
| `exist_and_search_upper_bound`(可解性条件)と | |
| `xMin_eq_D_mul_uMinOf` / `xMin_eq_neg_one_of_no_solution` を接続する。 | |
| 証明: `R=0` 可解/非可解と `R≠0` の 3 分岐で、`hbinR0`・`hbinRnz` と既存仕様補題を適用して示す。 | |
| 役割: 実装側 `compute_xMin` の正当性を確定する最上位定理。 | |
| -/ | |
| theorem compute_xMin_eq_xMin | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) : | |
| compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| have hExistPack := | |
| exist_and_search_upper_bound (D := D) (A := A) (B := B) (K := K) hD hA hB hK | |
| by_cases hR0 : Rof D A B = 0 | |
| · have hiff : | |
| HasUSolution D A B K hD hA hB ↔ D * K + gcdDA D A < A := | |
| (hExistPack.2.1 hR0) | |
| by_cases hcond : D * K + gcdDA D A < A | |
| · have hex : HasUSolution D A B K hD hA hB := (hiff.mpr hcond) | |
| have hcomp : | |
| compute_xMin D A B K = D * uMinOf D A B K hD hA hB hex := by | |
| have hnotle : ¬ A ≤ D * K + gcdDA D A := not_le.mpr hcond | |
| calc | |
| compute_xMin D A B K | |
| = D * compute_u_binary (B * K) (K + 1) (A / gcdDA D A) A B (Mof D A B) D hA := by | |
| simp only [compute_xMin, hD, ↓reduceDIte, hA, hB, hK, hR0, hnotle] | |
| _ = D * uMinOf D A B K hD hA hB hex := hbinR0 hD hA hB hK hex hR0 | |
| have hx : | |
| xMin D A B K hD hA hB = D * uMinOf D A B K hD hA hB hex := | |
| xMin_eq_D_mul_uMinOf (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| exact hcomp.trans hx.symm | |
| · have hnoU : ¬ HasUSolution D A B K hD hA hB := by | |
| exact fun hex => hcond (hiff.mp hex) | |
| have hno : ¬ ∃ u : Int, SolU D A B K hD hA hB u := by | |
| simpa only [not_exists, HasUSolution] using hnoU | |
| have hx : | |
| xMin D A B K hD hA hB = -1 := | |
| xMin_eq_neg_one_of_no_solution | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hno | |
| have hcomp : compute_xMin D A B K = -1 := by | |
| have hLe : A ≤ D * K + gcdDA D A := le_of_not_gt hcond | |
| simp only [compute_xMin, hD, ↓reduceDIte, hA, hB, hK, hR0, hLe, Int.reduceNeg] | |
| exact hcomp.trans hx.symm | |
| · have hex : HasUSolution D A B K hD hA hB := | |
| (hExistPack.1 hR0) | |
| have hcomp : | |
| compute_xMin D A B K = D * uMinOf D A B K hD hA hB hex := by | |
| simpa only [compute_xMin, hD, ↓reduceDIte, hA, hB, hK, hR0, mul_eq_mul_left_iff] using | |
| hbinRnz hD hA hB hK hex hR0 | |
| have hx : | |
| xMin D A B K hD hA hB = D * uMinOf D A B K hD hA hB hex := | |
| xMin_eq_D_mul_uMinOf (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| exact hcomp.trans hx.symm | |
| end ComputeCorrectness | |
| section DivmodD19Correctness | |
| /-- | |
| 目的: `divmod_d19_7e37` で使う除数定数 `10^19` を名前付きで定義する。 | |
| 定義: `D19 := 10^19`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 定理文で巨大定数の反復記述を避け、可読性を保つ。 | |
| -/ | |
| def D19 : Int := 10 ^ (19 : Nat) | |
| /-- | |
| 目的: `divmod_d19_125bit`, `divmod_d19_127bit` で使うシフト定数 `2^63` を名前付きで定義する。 | |
| 定義: `A63 := 2^63`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 近似商 `q = floor((floor(x/A)*M)/B)` の定数部を簡潔に書く。 | |
| -/ | |
| def A63 : Int := 2 ^ (63 : Nat) | |
| /-- | |
| 目的: `divmod_d19_128bit` で使うシフト定数 `2^64` を名前付きで定義する。 | |
| 定義: `A64 := 2^64`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `divmod_d19_128bit` の証明で `A` 側定数を簡潔に書く。 | |
| -/ | |
| def A64 : Int := 2 ^ (64 : Nat) | |
| /-- | |
| 目的: `divmod_d19_125bit`, `divmod_d19_127bit`, `divmod_d19_128bit` で使うシフト定数 `2^64` を名前付きで定義する。 | |
| 定義: `B64 := 2^64`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 近似商計算および `compute_xMin` の評価式を簡潔にする。 | |
| -/ | |
| def B64 : Int := 2 ^ (64 : Nat) | |
| /-- | |
| 目的: 125bit 版(最大 1 回補正)の想定範囲上端を定数として与える。 | |
| 定義: `xBound_d19_125bit := 78312161395427422060000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x < xBound_d19_125bit` から `Δ ≤ 1` を導く範囲条件として使う。 | |
| -/ | |
| def xBound_d19_125bit : Int := 78312161395427422060000000000000000000 | |
| /-- | |
| 目的: 127bit 版(最大 2 回補正)の想定範囲上端を定数として与える。 | |
| 定義: `xBound_d19_127bit := 1086673501021195308190000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x < xBound_d19_127bit` から `Δ ≤ 2` を導く範囲条件として使う。 | |
| -/ | |
| def xBound_d19_127bit : Int := 1086673501021195308190000000000000000000 | |
| /-- | |
| 目的: 128bit 版(最大 3 回補正)の想定範囲上端を定数として与える。 | |
| 定義: `xBound_d19_128bit := 1164985662416622730250000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x < xBound_d19_128bit` から `Δ ≤ 3` を導く範囲条件として使う。 | |
| -/ | |
| def xBound_d19_128bit : Int := 1164985662416622730250000000000000000000 | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hx : 0 ≤ x`。 | |
| 主張: `q := floor( floor(x/A) * floor(AB/D) / B )` は `q ≤ floor(x/D)` を満たす。 | |
| 内容: `q*B ≤ floor(x/A)*floor(AB/D)`、`floor(AB/D)*D ≤ AB`、 | |
| `floor(x/A)*A ≤ x` を順に連結して `q*D ≤ x` を得て、最後に `q ≤ x/D` に戻す。 | |
| 証明: `Int.ediv_mul_le` と単調性(正数倍)で示す。 | |
| 役割: `Delta = x/D - q` の非負性(`Delta ≥ 0`)を与える補助補題。 | |
| -/ | |
| lemma qApprox_le_trueQuot | |
| {D A B x : Int} | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (hx : 0 ≤ x) : | |
| (((x / A) * ((A * B) / D)) / B) ≤ x / D := by | |
| let u : Int := x / A | |
| let m : Int := (A * B) / D | |
| let q : Int := (u * m) / B | |
| have hD0 : D ≠ 0 := ne_of_gt hD | |
| have hA0 : A ≠ 0 := ne_of_gt hA | |
| have hB0 : B ≠ 0 := ne_of_gt hB | |
| have hu0 : 0 ≤ u := by | |
| dsimp only [u] | |
| exact Int.ediv_nonneg hx (le_of_lt hA) | |
| have hqB_le_um : q * B ≤ u * m := by | |
| dsimp only [q] | |
| simpa only [mul_comm] using (Int.ediv_mul_le (u * m) hB0) | |
| have hmD_le_AB : m * D ≤ A * B := by | |
| dsimp only [m] | |
| simpa only [mul_comm] using (Int.ediv_mul_le (A * B) hD0) | |
| have humD_le_uAB : (u * m) * D ≤ u * (A * B) := by | |
| have : u * (m * D) ≤ u * (A * B) := by | |
| exact mul_le_mul_of_nonneg_left hmD_le_AB hu0 | |
| simpa only [mul_assoc, ge_iff_le] using this | |
| have hAu_le_x : u * A ≤ x := by | |
| dsimp only [u] | |
| simpa only [mul_comm] using (Int.ediv_mul_le x hA0) | |
| have huAB_eq_uA_mul_B : u * (A * B) = (u * A) * B := by ring | |
| have huAB_le_xB : u * (A * B) ≤ x * B := by | |
| calc | |
| u * (A * B) = (u * A) * B := huAB_eq_uA_mul_B | |
| _ ≤ x * B := by | |
| exact mul_le_mul_of_nonneg_right hAu_le_x (le_of_lt hB) | |
| have hqBD_le_xB : (q * B) * D ≤ x * B := by | |
| calc | |
| (q * B) * D ≤ (u * m) * D := by | |
| exact mul_le_mul_of_nonneg_right hqB_le_um (le_of_lt hD) | |
| _ ≤ u * (A * B) := humD_le_uAB | |
| _ ≤ x * B := huAB_le_xB | |
| have hBqD_le_Bx : B * (q * D) ≤ B * x := by | |
| simpa only [mul_comm, mul_left_comm] using hqBD_le_xB | |
| have hqD_le_x : q * D ≤ x := by | |
| exact (Int.mul_le_mul_left hB).1 (by simpa only [mul_comm, mul_left_comm] using hBqD_le_Bx) | |
| have hq_le_div : q ≤ x / D := (Int.le_ediv_iff_mul_le hD).2 hqD_le_x | |
| simpa only [ge_iff_le] using hq_le_div | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hx0 : 0 ≤ x`, `x < xMin ...`。 | |
| 主張: `K < Delta D A B x` は成り立たない。 | |
| 内容: `x` が可解 (`SolX`) だと `xMinOf ≤ x` が従い `x < xMin` に矛盾する。 | |
| 逆に可解集合が空なら `K < Delta` から直ちに矛盾する。 | |
| 証明: `xMin` の場合分け(`∃ x, SolX`)と `csInf_le` で示す。 | |
| 役割: `x < xMin(… ,K)` から `Delta ≤ K` を導くための補助補題。 | |
| -/ | |
| lemma not_lt_Delta_of_lt_xMin | |
| {D A B K x : Int} | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (hx0 : 0 ≤ x) | |
| (hxMin : x < xMin D A B K hD hA hB) : | |
| ¬ (K < Delta D A B x hD hA hB) := by | |
| by_cases hexX : ∃ z : Int, SolX D A B K hD hA hB z | |
| · intro hKx | |
| have hBddX : BddBelow ({z : Int | SolX D A B K hD hA hB z} : Set Int) := by | |
| refine ⟨0, ?_⟩ | |
| intro z hz | |
| exact hz.1 | |
| have hxMinLe : xMinOf D A B K hD hA hB hexX ≤ x := by | |
| unfold xMinOf | |
| exact csInf_le hBddX ⟨hx0, hKx⟩ | |
| have hxMinEq : xMin D A B K hD hA hB = xMinOf D A B K hD hA hB hexX := by | |
| unfold xMin | |
| simp only [hexX, ↓reduceDIte] | |
| have hxMinLe' : xMin D A B K hD hA hB ≤ x := by | |
| simpa only [hxMinEq] using hxMinLe | |
| exact (not_le_of_gt hxMin) hxMinLe' | |
| · intro hKx | |
| exact hexX ⟨x, ⟨hx0, hKx⟩⟩ | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: 定数系 `(D19,A63,B64,K=1)` に対して `compute_xMin` は | |
| `xBound_d19_125bit` を返す。 | |
| 内容: 実装定義を計算評価して定数等式を得る。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: 125bit 範囲条件を `x < xMin(...,1)` に接続する。 | |
| -/ | |
| lemma compute_xMin_D19_A63_B64_K1 : | |
| compute_xMin D19 A63 B64 1 = xBound_d19_125bit := by | |
| set_option maxRecDepth 2000 in | |
| decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: 定数系 `(D19,A63,B64,K=2)` に対して `compute_xMin` は | |
| `xBound_d19_127bit` を返す。 | |
| 内容: 実装定義を計算評価して定数等式を得る。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: 127bit 範囲条件を `x < xMin(...,2)` に接続する。 | |
| -/ | |
| lemma compute_xMin_D19_A63_B64_K2 : | |
| compute_xMin D19 A63 B64 2 = xBound_d19_127bit := by | |
| set_option maxRecDepth 2000 in | |
| decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: 定数系 `(D19,A64,B64,K=3)` に対して `compute_xMin` は | |
| `xBound_d19_128bit` を返す。 | |
| 内容: 実装定義を計算評価して定数等式を得る。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: 128bit 範囲条件を `x < xMin(...,3)` に接続する。 | |
| -/ | |
| lemma compute_xMin_D19_A64_B64_K3 : | |
| compute_xMin D19 A64 B64 3 = xBound_d19_128bit := by | |
| set_option maxRecDepth 2000 in | |
| decide | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`, | |
| `hBound : compute_xMin D A B K = bound`, `hx : x < bound`。 | |
| 主張: `x < xMin D A B K hD hA hB`。 | |
| 内容: `compute_xMin_eq_xMin` で仕様値へ置換し、`bound` を経由して連鎖する。 | |
| 証明: 等式の書き換えと `calc` で示す。 | |
| 役割: 具体的な境界定数から `xMin` 仕様への橋渡しを共通化する。 | |
| -/ | |
| lemma lt_xMin_of_lt_compute_xMin_bound | |
| {D A B K x bound : Int} | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hBound : compute_xMin D A B K = bound) | |
| (hx : x < bound) : | |
| x < xMin D A B K hD hA hB := by | |
| have hxMinEqComp : compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| exact compute_xMin_eq_xMin (D := D) (A := A) (B := B) (K := K) hD hA hB hK | |
| calc | |
| x < bound := hx | |
| _ = compute_xMin D A B K := hBound.symm | |
| _ = xMin D A B K hD hA hB := hxMinEqComp | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`, | |
| `hx0 : 0 ≤ x`, `hBound : compute_xMin D A B K = bound`, `hx : x < bound`。 | |
| 主張: `0 ≤ Delta D A B x hD hA hB ∧ Delta D A B x hD hA hB ≤ K`。 | |
| 内容: 前半は `qApprox_le_trueQuot` から、後半は `x < xMin` を介して | |
| `not_lt_Delta_of_lt_xMin` から得る。 | |
| 証明: 既存補題を連結して示す。 | |
| 役割: 3つの `divmod_d19_*_correct_on_range` で共通の `Delta` 範囲導出をまとめる。 | |
| -/ | |
| lemma delta_bounds_of_lt_compute_xMin_bound | |
| {D A B K x bound : Int} | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hx0 : 0 ≤ x) | |
| (hBound : compute_xMin D A B K = bound) | |
| (hx : x < bound) : | |
| 0 ≤ Delta D A B x hD hA hB ∧ Delta D A B x hD hA hB ≤ K := by | |
| have hxLtXmin : x < xMin D A B K hD hA hB := by | |
| exact lt_xMin_of_lt_compute_xMin_bound | |
| (D := D) (A := A) (B := B) (K := K) (x := x) (bound := bound) | |
| hD hA hB hK hBound hx | |
| have hDeltaNotGt : ¬ K < Delta D A B x hD hA hB := by | |
| exact | |
| not_lt_Delta_of_lt_xMin | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hx0 hxLtXmin | |
| have hDeltaLe : Delta D A B x hD hA hB ≤ K := le_of_not_gt hDeltaNotGt | |
| have hqLe : (((x / A) * ((A * B) / D)) / B) ≤ x / D := by | |
| exact qApprox_le_trueQuot (D := D) (A := A) (B := B) hD hA hB hx0 | |
| have hDeltaNonneg : 0 ≤ Delta D A B x hD hA hB := by | |
| unfold Delta | |
| exact sub_nonneg.mpr hqLe | |
| exact ⟨hDeltaNonneg, hDeltaLe⟩ | |
| /-- | |
| 入力/前提: `hq` は `q = floor(floor(x/A) * floor(AB/D) / B)`。 | |
| 主張: `Delta D A B x ... = x / D - q`。 | |
| 内容: `Delta` の定義式に `hq` を代入する。 | |
| 証明: `subst` と定義展開で示す。 | |
| 役割: 各分岐で `Delta = 0,1,2,3` から `q` と真の商の関係を引く共通補題。 | |
| -/ | |
| lemma Delta_eq_div_sub_q | |
| {D A B x q : Int} | |
| (hD : 0 < D) (_hA : 0 < A) (_hB : 0 < B) | |
| (hq : q = (((x / A) * ((A * B) / D)) / B)) : | |
| Delta D A B x hD _hA _hB = x / D - q := by | |
| subst q | |
| unfold Delta | |
| rfl | |
| /-- | |
| 入力/前提: `hq` は `q = floor(floor(x/A) * floor(AB/D) / B)`。 | |
| 主張: `x - q*D = x%D + D*Delta D A B x ...`。 | |
| 内容: `x = D*(x/D) + x%D` と `Delta` の定義を組み合わせて式変形する。 | |
| 証明: 除算分解恒等式と `ring` で示す。 | |
| 役割: 各 `divmod` 証明で共通する `r` 展開(`r = x% D + D*Delta`)をまとめる。 | |
| -/ | |
| lemma sub_q_mul_eq_emod_add_Delta | |
| {D A B x q : Int} | |
| (hD : 0 < D) (_hA : 0 < A) (_hB : 0 < B) | |
| (hq : q = (((x / A) * ((A * B) / D)) / B)) : | |
| x - q * D = x % D + D * Delta D A B x hD _hA _hB := by | |
| have hxDecomp : D * (x / D) + x % D = x := by | |
| simpa only using (Int.mul_ediv_add_emod x D) | |
| have hxMinus : | |
| x - (((x / A) * ((A * B) / D)) / B) * D | |
| = (D * (x / D) + x % D) - (((x / A) * ((A * B) / D)) / B) * D := by | |
| exact | |
| (congrArg | |
| (fun t : Int => t - (((x / A) * ((A * B) / D)) / B) * D) | |
| hxDecomp).symm | |
| calc | |
| x - q * D | |
| = x - (((x / A) * ((A * B) / D)) / B) * D := by simp [hq] | |
| _ = (D * (x / D) + x % D) - (((x / A) * ((A * B) / D)) / B) * D := hxMinus | |
| _ = x % D + D * ((x / D) - (((x / A) * ((A * B) / D)) / B)) := by ring | |
| _ = x % D + D * Delta D A B x hD _hA _hB := by rfl | |
| /-- | |
| 入力/前提: `δ = x/D - q` かつ `δ = k`。 | |
| 主張: `q + k = x / D`。 | |
| 内容: 差分式を `k` に置換して線形方程式を解く。 | |
| 証明: 置換と `omega` で示す。 | |
| 役割: `δ` の各場合 (`0,1,2,3`) から商の一致を導く共通補題。 | |
| -/ | |
| lemma q_add_eq_div_of_delta_eq | |
| {x D q δ k : Int} | |
| (hDeltaEq : δ = x / D - q) | |
| (hδk : δ = k) : | |
| q + k = x / D := by | |
| have : x / D - q = k := by simpa only [hDeltaEq] using hδk | |
| omega | |
| /-- | |
| 入力/前提: `r = x%D + D*δ` かつ `δ = k`。 | |
| 主張: `r = x%D + D*k`。 | |
| 内容: `δ` を `k` に置換するだけ。 | |
| 証明: `simpa` で示す。 | |
| 役割: `δ` 固定時の `r` 形を共通で扱うための補助補題。 | |
| -/ | |
| lemma r_eq_rem_add_D_mul_of_delta_eq | |
| {D x r δ k : Int} | |
| (hrEq : r = x % D + D * δ) | |
| (hδk : δ = k) : | |
| r = x % D + D * k := by | |
| simpa only [hδk] using hrEq | |
| /-- | |
| 入力/前提: `r = x%D + D*δ` かつ `δ = k`。 | |
| 主張: `r - D*k = x%D`。 | |
| 内容: 上式を代入して整理する。 | |
| 証明: 置換後 `ring` で示す。 | |
| 役割: 補正後剰余が真の剰余に戻ることを共通で扱う補助補題。 | |
| -/ | |
| lemma r_sub_D_mul_eq_rem_of_delta_eq | |
| {D x r δ k : Int} | |
| (hrEq : r = x % D + D * δ) | |
| (hδk : δ = k) : | |
| r - D * k = x % D := by | |
| rw [hrEq, hδk] | |
| ring | |
| /-- | |
| 入力/前提: `0 < D`, `0 ≤ k`, `r = x%D + D*k`。 | |
| 主張: `D*k ≤ r`。 | |
| 内容: `x%D ≥ 0` を加えた下界を使う。 | |
| 証明: `Int.emod_nonneg` と `omega` で示す。 | |
| 役割: 分岐条件 `D*k ≤ r` を共通に導く補助補題。 | |
| -/ | |
| lemma ge_D_mul_of_r_eq_rem_add_D_mul | |
| {D x r k : Int} | |
| (hD : 0 < D) | |
| (hrEq : r = x % D + D * k) : | |
| D * k ≤ r := by | |
| have hRemNonneg : 0 ≤ x % D := Int.emod_nonneg x (ne_of_gt hD) | |
| rw [hrEq] | |
| omega | |
| /-- | |
| 入力/前提: `0 < D`, `0 ≤ k`, `k < m`, `r = x%D + D*k`。 | |
| 主張: `¬ D*m ≤ r`。 | |
| 内容: `x%D < D` より `r < D*(k+1) ≤ D*m` を示す。 | |
| 証明: `Int.emod_lt_of_pos` と `omega` で示す。 | |
| 役割: 上位分岐条件が偽であることを共通に導く補助補題。 | |
| -/ | |
| lemma not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| {D x r k m : Int} | |
| (hD : 0 < D) | |
| (hkm : k < m) | |
| (hrEq : r = x % D + D * k) : | |
| ¬ D * m ≤ r := by | |
| have hRemLt : x % D < D := Int.emod_lt_of_pos x hD | |
| have hkm1 : k + 1 ≤ m := (Int.lt_iff_add_one_le).1 hkm | |
| have hrlt : r < D * (k + 1) := by | |
| rw [hrEq] | |
| calc | |
| x % D + D * k < D + D * k := by | |
| simpa only [add_comm, add_left_comm, add_assoc] using | |
| (add_lt_add_right hRemLt (D * k)) | |
| _ = D * (k + 1) := by ring | |
| have hmul : D * (k + 1) ≤ D * m := by | |
| exact mul_le_mul_of_nonneg_left hkm1 (le_of_lt hD) | |
| exact not_le_of_gt (lt_of_lt_of_le hrlt hmul) | |
| /-- | |
| 入力/前提: `0 ≤ δ ≤ 1`, `δ = x/D - q`, `r = x%D + D*δ`, `0 < D`。 | |
| 主張: 1 段補正 | |
| `if D ≤ r then (q+1,r-D) else (q,r)` は `(x/D, x%D)` に一致する。 | |
| 内容: `δ ∈ {0,1}` の場合分けで示す。 | |
| 証明: 商剰余分解と不等式評価で示す。 | |
| 役割: `divmod_d19_125bit_correct_on_range` の分岐証明を共通化する。 | |
| -/ | |
| lemma divmod_if1_correct_of_delta_le1 | |
| {D x q r δ : Int} | |
| (hD : 0 < D) | |
| (hDeltaNonneg : 0 ≤ δ) | |
| (hDeltaLe1 : δ ≤ 1) | |
| (hDeltaEq : δ = x / D - q) | |
| (hrEq : r = x % D + D * δ) : | |
| (if D ≤ r then (q + 1, r - D) else (q, r)) = (x / D, x % D) := by | |
| have hDelta01 : δ = 0 ∨ δ = 1 := by | |
| omega | |
| rcases hDelta01 with hDelta0 | hDelta1 | |
| · have hqEq : q = x / D := by | |
| have hqEq0 : q + 0 = x / D := q_add_eq_div_of_delta_eq hDeltaEq hDelta0 | |
| omega | |
| have hrEqRem0 : r = x % D + D * 0 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta0 | |
| have hrEqRem : r = x % D := by simpa only [mul_zero, add_zero] using hrEqRem0 | |
| have hNotGe : ¬ D ≤ r := by | |
| have hNotGeMul1 : ¬ D * 1 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 0) (m := 1) | |
| hD (by decide) hrEqRem0 | |
| simpa only [mul_one] using hNotGeMul1 | |
| calc | |
| (if D ≤ r then (q + 1, r - D) else (q, r)) = (q, r) := by | |
| simp only [hNotGe, ↓reduceIte] | |
| _ = (x / D, x % D) := by simp only [hqEq, hrEqRem] | |
| · have hqPlusEq : q + 1 = x / D := by | |
| exact q_add_eq_div_of_delta_eq hDeltaEq hDelta1 | |
| have hrEqRem1 : r = x % D + D * 1 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta1 | |
| have hGe : D ≤ r := by | |
| have hGeMul1 : D * 1 ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 1) | |
| hD hrEqRem1 | |
| simpa only [mul_one] using hGeMul1 | |
| have hrSubEq : r - D = x % D := by | |
| have hrSubEq1 : r - D * 1 = x % D := r_sub_D_mul_eq_rem_of_delta_eq hrEq hDelta1 | |
| simpa only [mul_one] using hrSubEq1 | |
| calc | |
| (if D ≤ r then (q + 1, r - D) else (q, r)) = (q + 1, r - D) := by | |
| simp only [hGe, ↓reduceIte] | |
| _ = (x / D, x % D) := by simp only [hqPlusEq, hrSubEq] | |
| /-- | |
| 入力/前提: `0 ≤ δ ≤ 2`, `δ = x/D - q`, `r = x%D + D*δ`, `0 < D`。 | |
| 主張: 2 段補正 | |
| `if 2D ≤ r then (q+2,r-2D) else if D ≤ r then (q+1,r-D) else (q,r)` | |
| は `(x/D, x%D)` に一致する。 | |
| 内容: `δ ∈ {0,1,2}` の場合分けで示す。 | |
| 証明: 商剰余分解と不等式評価で示す。 | |
| 役割: `divmod_d19_127bit_correct_on_range` の分岐証明を共通化する。 | |
| -/ | |
| lemma divmod_if2_correct_of_delta_le2 | |
| {D x q r δ : Int} | |
| (hD : 0 < D) | |
| (hDeltaNonneg : 0 ≤ δ) | |
| (hDeltaLe2 : δ ≤ 2) | |
| (hDeltaEq : δ = x / D - q) | |
| (hrEq : r = x % D + D * δ) : | |
| (if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (x / D, x % D) := by | |
| have hDelta012 : δ = 0 ∨ δ = 1 ∨ δ = 2 := by | |
| omega | |
| rcases hDelta012 with hDelta0 | hDelta1 | hDelta2 | |
| · have hqEq : q = x / D := by | |
| have hqEq0 : q + 0 = x / D := q_add_eq_div_of_delta_eq hDeltaEq hDelta0 | |
| omega | |
| have hrEqRem0 : r = x % D + D * 0 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta0 | |
| have hrEqRem : r = x % D := by simpa only [mul_zero, add_zero] using hrEqRem0 | |
| have hNotGe1 : ¬ D ≤ r := by | |
| have hNotGeMul1 : ¬ D * 1 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 0) (m := 1) | |
| hD (by decide) hrEqRem0 | |
| simpa only [mul_one] using hNotGeMul1 | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 0) (m := 2) | |
| hD (by decide) hrEqRem0 | |
| calc | |
| (if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q, r) := by | |
| simp only [hNotGe2, ↓reduceIte, hNotGe1] | |
| _ = (x / D, x % D) := by simp only [hqEq, hrEqRem] | |
| · have hqPlusEq : q + 1 = x / D := by | |
| exact q_add_eq_div_of_delta_eq hDeltaEq hDelta1 | |
| have hrEqRem1' : r = x % D + D * 1 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta1 | |
| have hrEqRem1 : r = x % D + D := by simpa only [mul_one] using hrEqRem1' | |
| have hGe1 : D ≤ r := by | |
| have hGeMul1 : D * 1 ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 1) | |
| hD hrEqRem1' | |
| simpa only [mul_one] using hGeMul1 | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 1) (m := 2) | |
| hD (by decide) hrEqRem1' | |
| have hrSubEq : r - D = x % D := by | |
| have hrSubEq1 : r - D * 1 = x % D := r_sub_D_mul_eq_rem_of_delta_eq hrEq hDelta1 | |
| simpa only [mul_one] using hrSubEq1 | |
| calc | |
| (if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q + 1, r - D) := by | |
| simp only [hNotGe2, ↓reduceIte, hGe1] | |
| _ = (x / D, x % D) := by simp only [hqPlusEq, hrSubEq] | |
| · have hqPlus2Eq : q + 2 = x / D := by | |
| exact q_add_eq_div_of_delta_eq hDeltaEq hDelta2 | |
| have hrEqRem2 : r = x % D + D * 2 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta2 | |
| have hGe2 : D * 2 ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 2) | |
| hD hrEqRem2 | |
| have hrSub2Eq : r - D * 2 = x % D := by | |
| exact r_sub_D_mul_eq_rem_of_delta_eq hrEq hDelta2 | |
| calc | |
| (if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q + 2, r - D * 2) := by | |
| simp only [hGe2, ↓reduceIte] | |
| _ = (x / D, x % D) := by simp only [hqPlus2Eq, hrSub2Eq] | |
| /-- | |
| 入力/前提: `0 ≤ δ ≤ 3`, `δ = x/D - q`, `r = x%D + D*δ`, `0 < D`。 | |
| 主張: 3 段補正 | |
| `if 3D≤r then ... else if 2D≤r then ... else if D≤r then ... else ...` | |
| は `(x/D, x%D)` に一致する。 | |
| 内容: `δ ∈ {0,1,2,3}` の場合分けで示す。 | |
| 証明: 商剰余分解と不等式評価で示す。 | |
| 役割: `divmod_d19_128bit_correct_on_range` の分岐証明を共通化する。 | |
| -/ | |
| lemma divmod_if3_correct_of_delta_le3 | |
| {D x q r δ : Int} | |
| (hD : 0 < D) | |
| (hDeltaNonneg : 0 ≤ δ) | |
| (hDeltaLe3 : δ ≤ 3) | |
| (hDeltaEq : δ = x / D - q) | |
| (hrEq : r = x % D + D * δ) : | |
| (if D * 3 ≤ r then (q + 3, r - D * 3) | |
| else if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (x / D, x % D) := by | |
| have hDelta0123 : δ = 0 ∨ δ = 1 ∨ δ = 2 ∨ δ = 3 := by | |
| omega | |
| rcases hDelta0123 with hDelta0 | hDelta1 | hDelta2 | hDelta3 | |
| · have hqEq : q = x / D := by | |
| have hqEq0 : q + 0 = x / D := q_add_eq_div_of_delta_eq hDeltaEq hDelta0 | |
| omega | |
| have hrEqRem0 : r = x % D + D * 0 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta0 | |
| have hrEqRem : r = x % D := by simpa only [mul_zero, add_zero] using hrEqRem0 | |
| have hNotGe1 : ¬ D ≤ r := by | |
| have hNotGeMul1 : ¬ D * 1 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 0) (m := 1) | |
| hD (by decide) hrEqRem0 | |
| simpa only [mul_one] using hNotGeMul1 | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 0) (m := 2) | |
| hD (by decide) hrEqRem0 | |
| have hNotGe3 : ¬ D * 3 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 0) (m := 3) | |
| hD (by decide) hrEqRem0 | |
| calc | |
| (if D * 3 ≤ r then (q + 3, r - D * 3) | |
| else if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q, r) := by | |
| simp only [hNotGe3, ↓reduceIte, hNotGe2, hNotGe1] | |
| _ = (x / D, x % D) := by simp only [hqEq, hrEqRem] | |
| · have hqPlusEq : q + 1 = x / D := by | |
| exact q_add_eq_div_of_delta_eq hDeltaEq hDelta1 | |
| have hrEqRem1' : r = x % D + D * 1 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta1 | |
| have hrEqRem1 : r = x % D + D := by simpa only [mul_one] using hrEqRem1' | |
| have hGe1 : D ≤ r := by | |
| have hGeMul1 : D * 1 ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 1) | |
| hD hrEqRem1' | |
| simpa only [mul_one] using hGeMul1 | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 1) (m := 2) | |
| hD (by decide) hrEqRem1' | |
| have hNotGe3 : ¬ D * 3 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 1) (m := 3) | |
| hD (by decide) hrEqRem1' | |
| have hrSubEq : r - D = x % D := by | |
| have hrSubEq1 : r - D * 1 = x % D := r_sub_D_mul_eq_rem_of_delta_eq hrEq hDelta1 | |
| simpa only [mul_one] using hrSubEq1 | |
| calc | |
| (if D * 3 ≤ r then (q + 3, r - D * 3) | |
| else if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q + 1, r - D) := by | |
| simp only [hNotGe3, ↓reduceIte, hNotGe2, hGe1] | |
| _ = (x / D, x % D) := by simp only [hqPlusEq, hrSubEq] | |
| · have hqPlus2Eq : q + 2 = x / D := by | |
| exact q_add_eq_div_of_delta_eq hDeltaEq hDelta2 | |
| have hrEqRem2 : r = x % D + D * 2 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta2 | |
| have hGe2 : D * 2 ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 2) | |
| hD hrEqRem2 | |
| have hNotGe3 : ¬ D * 3 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 2) (m := 3) | |
| hD (by decide) hrEqRem2 | |
| have hrSub2Eq : r - D * 2 = x % D := by | |
| exact r_sub_D_mul_eq_rem_of_delta_eq hrEq hDelta2 | |
| calc | |
| (if D * 3 ≤ r then (q + 3, r - D * 3) | |
| else if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q + 2, r - D * 2) := by | |
| simp only [hNotGe3, ↓reduceIte, hGe2] | |
| _ = (x / D, x % D) := by simp only [hqPlus2Eq, hrSub2Eq] | |
| · have hqPlus3Eq : q + 3 = x / D := by | |
| exact q_add_eq_div_of_delta_eq hDeltaEq hDelta3 | |
| have hrEqRem3 : r = x % D + D * 3 := r_eq_rem_add_D_mul_of_delta_eq hrEq hDelta3 | |
| have hGe3 : D * 3 ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := 3) | |
| hD hrEqRem3 | |
| have hrSub3Eq : r - D * 3 = x % D := by | |
| exact r_sub_D_mul_eq_rem_of_delta_eq hrEq hDelta3 | |
| calc | |
| (if D * 3 ≤ r then (q + 3, r - D * 3) | |
| else if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) = (q + 3, r - D * 3) := by | |
| simp only [hGe3, ↓reduceIte] | |
| _ = (x / D, x % D) := by simp only [hqPlus3Eq, hrSub3Eq] | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d19_125bit`。 | |
| 主張: `divmod_d19_125bit x = divmod_d19 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 1` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if1_correct_of_delta_le1` を適用して結論を得る。 | |
| 証明: 既存の共通補題を連結して示す。 | |
| 役割: `divmod_d19_125bit` の利用域における正当性保証を与える。 | |
| -/ | |
| theorem divmod_d19_125bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < xBound_d19_125bit) : | |
| divmod_d19_125bit x = divmod_d19 x := by | |
| have hD : 0 < D19 := by decide | |
| have hA : 0 < A63 := by decide | |
| have hB : 0 < B64 := by decide | |
| have hK : 0 ≤ (1 : Int) := by decide | |
| have hDeltaBounds : 0 ≤ Delta D19 A63 B64 x hD hA hB ∧ Delta D19 A63 B64 x hD hA hB ≤ 1 := by | |
| exact | |
| delta_bounds_of_lt_compute_xMin_bound | |
| (D := D19) (A := A63) (B := B64) (K := 1) (x := x) (bound := xBound_d19_125bit) | |
| hD hA hB hK hx0 compute_xMin_D19_A63_B64_K1 hx | |
| have hDeltaNonneg : 0 ≤ Delta D19 A63 B64 x hD hA hB := hDeltaBounds.1 | |
| have hDeltaLe1 : Delta D19 A63 B64 x hD hA hB ≤ 1 := hDeltaBounds.2 | |
| let M : Int := A63 * B64 / D19 | |
| let q : Int := ((x / A63) * M) / B64 | |
| let r : Int := x - q * D19 | |
| have hqDef : q = (((x / A63) * ((A63 * B64) / D19)) / B64) := by | |
| simp [M, q] | |
| have hDivmod : | |
| divmod_d19_125bit x = if D19 ≤ r then (q + 1, r - D19) else (q, r) := by | |
| unfold divmod_d19_125bit | |
| simp only [Int.reducePow, Int.reduceMul, Int.reduceDiv, D19, A63, B64, r, q, M] | |
| have hDeltaEq : Delta D19 A63 B64 x hD hA hB = x / D19 - q := by | |
| exact Delta_eq_div_sub_q (D := D19) (A := A63) (B := B64) (x := x) (q := q) hD hA hB hqDef | |
| have hrEq : r = x % D19 + D19 * Delta D19 A63 B64 x hD hA hB := by | |
| calc | |
| r = x - q * D19 := by rfl | |
| _ = x % D19 + D19 * Delta D19 A63 B64 x hD hA hB := by | |
| simpa only [hqDef] using | |
| (sub_q_mul_eq_emod_add_Delta (D := D19) (A := A63) (B := B64) (x := x) (q := q) hD hA | |
| hB hqDef) | |
| have hCore : | |
| (if D19 ≤ r then (q + 1, r - D19) else (q, r)) = (x / D19, x % D19) := by | |
| exact | |
| divmod_if1_correct_of_delta_le1 | |
| (D := D19) (x := x) (q := q) (r := r) (δ := Delta D19 A63 B64 x hD hA hB) | |
| hD hDeltaNonneg hDeltaLe1 hDeltaEq hrEq | |
| calc | |
| divmod_d19_125bit x = if D19 ≤ r then (q + 1, r - D19) else (q, r) := hDivmod | |
| _ = (x / D19, x % D19) := hCore | |
| _ = divmod_d19 x := by simp only [divmod_d19, D19] | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d19_127bit`。 | |
| 主張: `divmod_d19_127bit x = divmod_d19 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 2` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if2_correct_of_delta_le2` を適用して結論を得る。 | |
| 証明: 既存の共通補題を連結して示す。 | |
| 役割: `divmod_d19_127bit` の利用域における正当性保証を与える。 | |
| -/ | |
| theorem divmod_d19_127bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < xBound_d19_127bit) : | |
| divmod_d19_127bit x = divmod_d19 x := by | |
| have hD : 0 < D19 := by decide | |
| have hA : 0 < A63 := by decide | |
| have hB : 0 < B64 := by decide | |
| have hK : 0 ≤ (2 : Int) := by decide | |
| have hDeltaBounds : 0 ≤ Delta D19 A63 B64 x hD hA hB ∧ Delta D19 A63 B64 x hD hA hB ≤ 2 := by | |
| exact | |
| delta_bounds_of_lt_compute_xMin_bound | |
| (D := D19) (A := A63) (B := B64) (K := 2) (x := x) (bound := xBound_d19_127bit) | |
| hD hA hB hK hx0 compute_xMin_D19_A63_B64_K2 hx | |
| have hDeltaNonneg : 0 ≤ Delta D19 A63 B64 x hD hA hB := hDeltaBounds.1 | |
| have hDeltaLe2 : Delta D19 A63 B64 x hD hA hB ≤ 2 := hDeltaBounds.2 | |
| let M : Int := A63 * B64 / D19 | |
| let q : Int := ((x / A63) * M) / B64 | |
| let r : Int := x - q * D19 | |
| have hqDef : q = (((x / A63) * ((A63 * B64) / D19)) / B64) := by | |
| simp only [q, M] | |
| have hDivmod : | |
| divmod_d19_127bit x = | |
| if D19 * 2 ≤ r then (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then (q + 1, r - D19) | |
| else (q, r) := by | |
| unfold divmod_d19_127bit | |
| simp only [Int.reducePow, Int.reduceMul, Int.reduceDiv, D19, A63, B64, r, q, M] | |
| have hDeltaEq : Delta D19 A63 B64 x hD hA hB = x / D19 - q := by | |
| exact Delta_eq_div_sub_q (D := D19) (A := A63) (B := B64) (x := x) (q := q) hD hA hB hqDef | |
| have hrEq : r = x % D19 + D19 * Delta D19 A63 B64 x hD hA hB := by | |
| calc | |
| r = x - q * D19 := by rfl | |
| _ = x % D19 + D19 * Delta D19 A63 B64 x hD hA hB := by | |
| simpa only [hqDef] using | |
| (sub_q_mul_eq_emod_add_Delta (D := D19) (A := A63) (B := B64) (x := x) (q := q) hD hA | |
| hB hqDef) | |
| have hCore : | |
| (if D19 * 2 ≤ r then (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then (q + 1, r - D19) | |
| else (q, r)) = (x / D19, x % D19) := by | |
| exact | |
| divmod_if2_correct_of_delta_le2 | |
| (D := D19) (x := x) (q := q) (r := r) (δ := Delta D19 A63 B64 x hD hA hB) | |
| hD hDeltaNonneg hDeltaLe2 hDeltaEq hrEq | |
| calc | |
| divmod_d19_127bit x = | |
| if D19 * 2 ≤ r then (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then (q + 1, r - D19) | |
| else (q, r) := hDivmod | |
| _ = (x / D19, x % D19) := hCore | |
| _ = divmod_d19 x := by simp only [divmod_d19, D19] | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d19_128bit`。 | |
| 主張: `divmod_d19_128bit x = divmod_d19 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 3` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if3_correct_of_delta_le3` を適用して結論を得る。 | |
| 証明: 既存の共通補題を連結して示す。 | |
| 役割: `divmod_d19_128bit` の利用域における正当性保証を与える。 | |
| -/ | |
| theorem divmod_d19_128bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < xBound_d19_128bit) : | |
| divmod_d19_128bit x = divmod_d19 x := by | |
| have hD : 0 < D19 := by decide | |
| have hA : 0 < A64 := by decide | |
| have hB : 0 < B64 := by decide | |
| have hK : 0 ≤ (3 : Int) := by decide | |
| have hDeltaBounds : 0 ≤ Delta D19 A64 B64 x hD hA hB ∧ Delta D19 A64 B64 x hD hA hB ≤ 3 := by | |
| exact | |
| delta_bounds_of_lt_compute_xMin_bound | |
| (D := D19) (A := A64) (B := B64) (K := 3) (x := x) (bound := xBound_d19_128bit) | |
| hD hA hB hK hx0 compute_xMin_D19_A64_B64_K3 hx | |
| have hDeltaNonneg : 0 ≤ Delta D19 A64 B64 x hD hA hB := hDeltaBounds.1 | |
| have hDeltaLe3 : Delta D19 A64 B64 x hD hA hB ≤ 3 := hDeltaBounds.2 | |
| let M : Int := A64 * B64 / D19 | |
| let q : Int := ((x / A64) * M) / B64 | |
| let r : Int := x - q * D19 | |
| have hqDef : q = (((x / A64) * ((A64 * B64) / D19)) / B64) := by | |
| simp only [q, M] | |
| have hDivmod : | |
| divmod_d19_128bit x = | |
| if D19 * 3 ≤ r then (q + 3, r - D19 * 3) | |
| else if D19 * 2 ≤ r then (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then (q + 1, r - D19) | |
| else (q, r) := by | |
| unfold divmod_d19_128bit | |
| simp only [Int.reducePow, Int.reduceMul, Int.reduceDiv, D19, A64, B64, r, q, M] | |
| have hDeltaEq : Delta D19 A64 B64 x hD hA hB = x / D19 - q := by | |
| exact Delta_eq_div_sub_q (D := D19) (A := A64) (B := B64) (x := x) (q := q) hD hA hB hqDef | |
| have hrEq : r = x % D19 + D19 * Delta D19 A64 B64 x hD hA hB := by | |
| calc | |
| r = x - q * D19 := by rfl | |
| _ = x % D19 + D19 * Delta D19 A64 B64 x hD hA hB := by | |
| simpa only [hqDef] using | |
| (sub_q_mul_eq_emod_add_Delta (D := D19) (A := A64) (B := B64) (x := x) (q := q) hD hA | |
| hB hqDef) | |
| have hCore : | |
| (if D19 * 3 ≤ r then (q + 3, r - D19 * 3) | |
| else if D19 * 2 ≤ r then (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then (q + 1, r - D19) | |
| else (q, r)) = (x / D19, x % D19) := by | |
| exact | |
| divmod_if3_correct_of_delta_le3 | |
| (D := D19) (x := x) (q := q) (r := r) (δ := Delta D19 A64 B64 x hD hA hB) | |
| hD hDeltaNonneg hDeltaLe3 hDeltaEq hrEq | |
| calc | |
| divmod_d19_128bit x = | |
| if D19 * 3 ≤ r then (q + 3, r - D19 * 3) | |
| else if D19 * 2 ≤ r then (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then (q + 1, r - D19) | |
| else (q, r) := hDivmod | |
| _ = (x / D19, x % D19) := hCore | |
| _ = divmod_d19 x := by simp only [divmod_d19, D19] | |
| end DivmodD19Correctness | |
| end Divapprox |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Mathlib.Data.Int.Basic | |
| import Mathlib.Data.Int.Lemmas | |
| import Mathlib.Data.Int.Fib.Basic | |
| import Mathlib.Data.Finset.Basic | |
| import Mathlib.Data.Nat.Fib.Zeckendorf | |
| import Mathlib.Data.Real.Basic | |
| import Mathlib.Analysis.SpecialFunctions.Sqrt | |
| import Mathlib.Analysis.SpecialFunctions.Log.Base | |
| import Mathlib.NumberTheory.Real.GoldenRatio | |
| import Mathlib.Tactic | |
| namespace Fib | |
| /-- | |
| 目的: `Nat.greatestFib` と同値な逐次生成版を定義する。 | |
| 定義: `(F_k, F_{k+1})` を更新し、`F_{k+1} ≤ n` の間だけ `k` を進める。 | |
| 入力/前提: `n : Nat`、再帰引数 `fuel k fk fk1 : Nat`。 | |
| 出力: 型 `Nat` の値を返す。 | |
| 役割: 計算目的で軽量な `greatestFib` 代替を与える。 | |
| -/ | |
| private def greatestFibIter_go (n : Nat) : Nat → Nat → Nat → Nat → Nat | |
| | 0, k, _, _ => k | |
| | fuel + 1, k, fk, fk1 => | |
| if _ : fk1 ≤ n then | |
| greatestFibIter_go n fuel (k + 1) fk1 (fk + fk1) | |
| else k | |
| /-- | |
| 目的: `Nat.greatestFib` と同値な逐次生成版を定義する。 | |
| 定義: `(F_k, F_{k+1})` を更新し、`F_{k+1} ≤ n` の間だけ `k` を進める。 | |
| 入力/前提: n : Nat。 | |
| 出力: 型 `Nat` の値を返す。 | |
| 役割: 計算目的で軽量な `greatestFib` 代替を与える。 | |
| -/ | |
| def greatestFibIter (n : Nat) : Nat := | |
| greatestFibIter_go n (n + 2) 0 0 1 | |
| /-- | |
| 入力/前提: k : Nat。 | |
| 主張: `k ≤ fib (k+1)` を与える補助補題。 | |
| 内容: `Nat.le_fib_add_one` を `k+1` に適用して `k ≤ fib (k+1)` を取り出す。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `n < fib (n+2)` の導出に使う基礎評価。 | |
| -/ | |
| private lemma fib_succ_ge (k : Nat) : k ≤ Nat.fib (k + 1) := by | |
| have h := Nat.le_fib_add_one (k + 1) | |
| exact (Nat.succ_le_succ_iff.mp h) | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `n < fib (n+2)` を与える補助補題。 | |
| 内容: `fib (n+2)` の下界 `n+1 ≤ fib (n+2)` を `fib_succ_ge` から得て推論する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 燃料が尽きるケースの矛盾導出に使う。 | |
| -/ | |
| private lemma lt_fib_succ_succ (n : Nat) : n < Nat.fib (n + 2) := by | |
| have h1 : n + 1 ≤ Nat.fib (n + 2) := by | |
| simpa only [Order.add_one_le_iff] using (fib_succ_ge (n + 1)) | |
| exact lt_of_lt_of_le (Nat.lt_succ_self n) h1 | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: 反復版 `greatestFibIter_go` が `Nat.greatestFib` を返す。 | |
| 内容: 不変量 `fk = fib k`, `fk1 = fib (k+1)` と `fib k ≤ n`, `k+fuel = n+2` のもとで | |
| 反復の分岐を追い、`fk1 ≤ n` なら次状態、そうでなければ最大性から `k` を確定する。 | |
| 証明: 帰納法・場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `greatestFibIter` の正しさを示す中核補題。 | |
| -/ | |
| private lemma greatestFibIter_go_eq (n : Nat) : | |
| ∀ fuel k fk fk1, | |
| fk = Nat.fib k → | |
| fk1 = Nat.fib (k + 1) → | |
| Nat.fib k ≤ n → | |
| k + fuel = n + 2 → | |
| greatestFibIter_go n fuel k fk fk1 = Nat.greatestFib n := by | |
| intro fuel k fk fk1 hk hk1 hk_le hfuel | |
| induction fuel generalizing k fk fk1 with | |
| | zero => | |
| exfalso | |
| have hk' : k = n + 2 := by simpa only [add_zero] using hfuel | |
| have hle : Nat.fib (n + 2) ≤ n := by simpa only [hk'] using hk_le | |
| have hlt : n < Nat.fib (n + 2) := lt_fib_succ_succ n | |
| exact (lt_irrefl n) (lt_of_lt_of_le hlt hle) | |
| | succ fuel ih => | |
| by_cases h : fk1 ≤ n | |
| · have hk2 : fk + fk1 = Nat.fib (k + 2) := by | |
| calc | |
| fk + fk1 = Nat.fib k + Nat.fib (k + 1) := by simp only [hk, hk1] | |
| _ = Nat.fib (k + 2) := by | |
| symm | |
| simpa only using (Nat.fib_add_two (n := k)) | |
| have hk_le' : Nat.fib (k + 1) ≤ n := by simpa only [hk1] using h | |
| have hfuel' : k + 1 + fuel = n + 2 := by | |
| calc | |
| k + 1 + fuel = k + (1 + fuel) := by simp only [Nat.add_assoc] | |
| _ = k + (fuel + 1) := by simp only [Nat.add_comm] | |
| _ = n + 2 := hfuel | |
| have ih' := | |
| ih (k := k + 1) (fk := fk1) (fk1 := fk + fk1) hk1 hk2 hk_le' hfuel' | |
| simpa only [greatestFibIter_go, h, ↓reduceDIte] using ih' | |
| · have hk_le_g : k ≤ Nat.greatestFib n := | |
| (Nat.le_greatestFib (m := k) (n := n)).2 hk_le | |
| have hlt' : n < Nat.fib (k + 1) := by | |
| have h' : n < fk1 := lt_of_not_ge h | |
| simpa only [gt_iff_lt, hk1] using h' | |
| have hgf_lt : Nat.greatestFib n < k + 1 := | |
| (Nat.greatestFib_lt (m := n) (n := k + 1)).2 hlt' | |
| have hgf_le : Nat.greatestFib n ≤ k := Nat.le_of_lt_succ hgf_lt | |
| have hk_eq : k = Nat.greatestFib n := le_antisymm hk_le_g hgf_le | |
| simpa only [greatestFibIter_go, h, ↓reduceDIte] using hk_eq | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `greatestFibIter` は `Nat.greatestFib` と一致する。 | |
| 内容: 初期値 `(k,fk,fk1)=(0,0,1)` と燃料 `n+2` を `greatestFibIter_go_eq` に適用する。 | |
| 証明: `greatestFibIter_go_eq` へ初期値を代入して示す。 | |
| 役割: 反復実装 `greatestFibIter` を `Nat.greatestFib` に置き換える根拠。 | |
| -/ | |
| @[simp] | |
| theorem greatestFibIter_eq_greatestFib (n : Nat) : | |
| greatestFibIter n = Nat.greatestFib n := by | |
| have h0 : Nat.fib 0 ≤ n := by simp | |
| have h := greatestFibIter_go_eq (n := n) (fuel := n + 2) (k := 0) (fk := 0) (fk1 := 1) | |
| rfl rfl h0 (by simp) | |
| simpa only [greatestFibIter] using h | |
| /-! ### Binet formula and floor/log characterization -/ | |
| noncomputable section | |
| open scoped goldenRatio | |
| local notation "fib" => Nat.fib | |
| /-- | |
| 目的: 黄金比 `phi` を定義する。 | |
| 定義: `phi` を `Real.goldenRatio`(`(1 + √5) / 2`)の別名として置く。 | |
| 入力/前提: 追加の仮定なし。 | |
| 出力: 型 `Real` の値を返す。 | |
| 役割: Binet 公式および `log_φ` による添字評価の基底として使う。 | |
| -/ | |
| abbrev phi : Real := Real.goldenRatio | |
| /-- | |
| 目的: 黄金比の共役 `psi` を定義する。 | |
| 定義: `psi` を `Real.goldenConj`(`(1 - √5) / 2`)の別名として置く。 | |
| 入力/前提: 追加の仮定なし。 | |
| 出力: 型 `Real` の値を返す。 | |
| 役割: Binet 公式の誤差項 `psi^n` を扱うための定数を固定する。 | |
| -/ | |
| abbrev psi : Real := Real.goldenConj | |
| /-- | |
| 入力/前提: n : Nat、fib n : Real。 | |
| 主張: 実数埋め込みしたフィボナッチ数に対する Binet 公式。 | |
| 内容: `Real.coe_fib_eq` を `phi`, `psi` の別名へ読み替える。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 以降の誤差評価および境界不等式の基本式を与える。 | |
| -/ | |
| lemma fib_binet (n : Nat) : | |
| (fib n : Real) = (phi ^ n - psi ^ n) / Real.sqrt 5 := by | |
| simpa only [phi, psi] using (Real.coe_fib_eq n) | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `fib n` は `phi^n/√5` の `1/2` 未満の誤差で近似される。 | |
| 内容: `fib_binet` の誤差項 `psi^n/√5` を `|psi| < 1` と `√5 > 2` で評価し、 | |
| 絶対値不等式から上下評価へ変換する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `floor(log_φ(...))` と `fib` 区間条件を接続するための数値境界を与える。 | |
| -/ | |
| lemma fib_binet_bounds (n : Nat) : | |
| phi ^ n / Real.sqrt 5 - (1 / 2 : Real) < (fib n : Real) ∧ | |
| (fib n : Real) < phi ^ n / Real.sqrt 5 + (1 / 2 : Real) := by | |
| have hsqrt5_pos : 0 < Real.sqrt 5 := by | |
| have h : (0 : Real) < 5 := by norm_num | |
| exact Real.sqrt_pos.2 h | |
| have hpsi_neg : psi < 0 := by | |
| simpa only [psi] using Real.goldenConj_neg | |
| have hneg_one_lt_psi : (-1 : Real) < psi := by | |
| simpa only [psi] using Real.neg_one_lt_goldenConj | |
| have habs_psi_lt_one : |psi| < (1 : Real) := by | |
| exact abs_lt.2 ⟨hneg_one_lt_psi, by linarith⟩ | |
| have habs_psi_pow_le_one : |psi| ^ n ≤ (1 : Real) := by | |
| calc | |
| |psi| ^ n ≤ (1 : Real) := by | |
| exact pow_le_one₀ (abs_nonneg psi) (le_of_lt habs_psi_lt_one) | |
| _ = 1 := by simp | |
| have hsqrt5_gt2 : (2 : Real) < Real.sqrt 5 := by | |
| refine (Real.lt_sqrt (show (0 : Real) ≤ (2 : Real) by norm_num)).2 ?_ | |
| norm_num | |
| have hone_div_sqrt5_lt_half : (1 : Real) / Real.sqrt 5 < (1 : Real) / 2 := by | |
| simpa only [one_div] using | |
| (one_div_lt_one_div_of_lt (show (0 : Real) < 2 by norm_num) hsqrt5_gt2) | |
| have habs_err_le : |psi ^ n / Real.sqrt 5| ≤ (1 : Real) / Real.sqrt 5 := by | |
| calc | |
| |psi ^ n / Real.sqrt 5| = |psi| ^ n / Real.sqrt 5 := by | |
| rw [abs_div, abs_pow, abs_of_pos hsqrt5_pos] | |
| _ ≤ (1 : Real) / Real.sqrt 5 := by | |
| exact div_le_div_of_nonneg_right habs_psi_pow_le_one (le_of_lt hsqrt5_pos) | |
| have herr : | |
| (fib n : Real) - phi ^ n / Real.sqrt 5 = -(psi ^ n / Real.sqrt 5) := by | |
| have hsqrt5_ne : (Real.sqrt 5) ≠ 0 := ne_of_gt hsqrt5_pos | |
| rw [fib_binet] | |
| field_simp [hsqrt5_ne] | |
| ring | |
| have habs_main : |(fib n : Real) - phi ^ n / Real.sqrt 5| < (1 / 2 : Real) := by | |
| rw [herr, abs_neg] | |
| exact lt_of_le_of_lt habs_err_le hone_div_sqrt5_lt_half | |
| have habs_split : | |
| (-(1 / 2 : Real) < (fib n : Real) - phi ^ n / Real.sqrt 5) ∧ | |
| ((fib n : Real) - phi ^ n / Real.sqrt 5 < (1 / 2 : Real)) := abs_lt.mp habs_main | |
| constructor <;> linarith [habs_split.1, habs_split.2] | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `fib_binet_bounds` の下側評価を取り出す。 | |
| 内容: 連言の左成分を返すだけ。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 後続補題で下界のみ使う場面を簡潔化する。 | |
| -/ | |
| lemma fib_binet_lower (n : Nat) : | |
| phi ^ n / Real.sqrt 5 - (1 / 2 : Real) < (fib n : Real) := by | |
| exact (fib_binet_bounds n).1 | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `fib_binet_bounds` の上側評価を取り出す。 | |
| 内容: 連言の右成分を返すだけ。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 後続補題で上界のみ使う場面を簡潔化する。 | |
| -/ | |
| lemma fib_binet_upper (n : Nat) : | |
| (fib n : Real) < phi ^ n / Real.sqrt 5 + (1 / 2 : Real) := by | |
| exact (fib_binet_bounds n).2 | |
| /-- | |
| 目的: `floor/log` 連鎖で使う引数 `logArg` を定義する。 | |
| 定義: `logArg n = √5 * (n + 1/2)` と置く。 | |
| 入力/前提: n : Nat。 | |
| 出力: 型 `Real` の値を返す。 | |
| 役割: `log_φ` 側の不等式と `fib` 側の近似不等式を同一の式で橋渡しする。 | |
| -/ | |
| def logArg (n : Nat) : Real := Real.sqrt 5 * ((n : Real) + (1 / 2 : Real)) | |
| /-- | |
| 目的: `phi` を底とする対数 `logPhi` を定義する。 | |
| 定義: `logPhi x := Real.logb phi x`。 | |
| 入力/前提: x : Real。 | |
| 出力: 型 `Real` の値を返す。 | |
| 役割: 添字 `k` を `floor(log_φ(...))` で記述する主定理の記号を固定する。 | |
| -/ | |
| def logPhi (x : Real) : Real := Real.logb phi x | |
| /-- | |
| 入力/前提: 追加の仮定なし。 | |
| 主張: `1 < phi` が成り立つ。 | |
| 内容: `Real.one_lt_goldenRatio` を別名定義に移送する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `logb` と `rpow` の同値変形で必要な底条件を供給する。 | |
| -/ | |
| lemma one_lt_phi : 1 < phi := by | |
| simpa only [phi] using Real.one_lt_goldenRatio | |
| /-- | |
| 入力/前提: 追加の仮定なし。 | |
| 主張: `sqrt 5` は正である。 | |
| 内容: `Real.sqrt_pos` を `5 > 0` に適用する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 除算・乗除不等式変形(`div_le_iff₀`, `lt_div_iff₀`)の前提に使う。 | |
| -/ | |
| lemma sqrt5_pos : 0 < Real.sqrt 5 := by | |
| have h : (0 : Real) < 5 := by norm_num | |
| exact Real.sqrt_pos.2 h | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `logArg n` は正である。 | |
| 内容: `logArg` を展開し、`sqrt5_pos` と `(n : Real) + 1/2 > 0` の積として示す。 | |
| 証明: 式変形で示す。 | |
| 役割: `Real.le_logb_iff_rpow_le` など `logb` の正引数条件を満たす。 | |
| -/ | |
| lemma logArg_pos (n : Nat) : 0 < logArg n := by | |
| unfold logArg | |
| have hM : (0 : Real) < (n : Real) + (1 / 2 : Real) := by | |
| have hM0 : (0 : Real) ≤ (n : Real) := by positivity | |
| linarith | |
| exact mul_pos sqrt5_pos hM | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `k = floor(logPhi(logArg n))` の同値条件を区間不等式で与える。 | |
| 内容: `Int.floor_eq_iff` を適用し、`(k : Real)+1` を `(k+1 : Real)` に正規化する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `floor` 記述から連続量の不等式記述への最初の変換を担う。 | |
| -/ | |
| lemma floor_logPhi_iff (k n : Nat) : | |
| (k : Int) = Int.floor (logPhi (logArg n)) ↔ | |
| ((k : Real) ≤ logPhi (logArg n) ∧ logPhi (logArg n) < (k + 1 : Real)) := by | |
| constructor | |
| · intro hk | |
| have h' : | |
| ((k : Real) ≤ logPhi (logArg n) ∧ logPhi (logArg n) < (k : Real) + 1) := | |
| (Int.floor_eq_iff).1 hk.symm | |
| simpa only using h' | |
| · intro hk | |
| have h' : | |
| ((k : Real) ≤ logPhi (logArg n) ∧ logPhi (logArg n) < (k : Real) + 1) := by | |
| simpa only using hk | |
| exact ((Int.floor_eq_iff).2 h').symm | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `logPhi` の区間不等式と `phi` のべき不等式は同値である。 | |
| 内容: 底条件 `one_lt_phi` と引数正条件 `logArg_pos` の下で、 | |
| `Real.le_logb_iff_rpow_le` と `Real.logb_lt_iff_lt_rpow` を往復適用する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 対数表現から指数表現へ移る中核変換。 | |
| -/ | |
| lemma logPhi_bounds_iff_pow_bounds (k n : Nat) : | |
| ((k : Real) ≤ logPhi (logArg n) ∧ logPhi (logArg n) < (k + 1 : Real)) ↔ | |
| (phi ^ k ≤ logArg n ∧ logArg n < phi ^ (k + 1)) := by | |
| constructor | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| have h1' : phi ^ (k : Real) ≤ logArg n := | |
| (Real.le_logb_iff_rpow_le one_lt_phi (logArg_pos n)).1 h1 | |
| have h2' : logArg n < phi ^ ((k : Real) + 1) := by | |
| have h2k : logPhi (logArg n) < (k : Real) + 1 := by | |
| simpa only using h2 | |
| exact (Real.logb_lt_iff_lt_rpow one_lt_phi (logArg_pos n)).1 h2k | |
| have h2nat : logArg n < phi ^ (k + 1) := by | |
| rw [← Real.rpow_natCast] | |
| simpa only [Nat.cast_add, Nat.cast_one] using h2' | |
| exact ⟨ | |
| by simpa only [Real.rpow_natCast] using h1', | |
| h2nat⟩ | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| have h1' : phi ^ (k : Real) ≤ logArg n := by | |
| simpa only [Real.rpow_natCast] using h1 | |
| have h2r := h2 | |
| rw [← Real.rpow_natCast] at h2r | |
| have h2' : logArg n < phi ^ ((k : Real) + 1) := by | |
| simpa only [Nat.cast_add, Nat.cast_one] using h2r | |
| exact ⟨ | |
| (Real.le_logb_iff_rpow_le one_lt_phi (logArg_pos n)).2 h1', | |
| by | |
| have : logPhi (logArg n) < (k : Real) + 1 := | |
| (Real.logb_lt_iff_lt_rpow one_lt_phi (logArg_pos n)).2 h2' | |
| simpa only [gt_iff_lt] using this⟩ | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `phi` のべき境界と `n` の平行移動境界は同値である。 | |
| 内容: `logArg = √5*(n+1/2)` を展開し、`sqrt5_pos` を使った乗除不等式変形で | |
| `phi^k/√5 - 1/2 ≤ n < phi^(k+1)/√5 - 1/2` へ整理する。 | |
| 証明: 式変形で示す。 | |
| 役割: 解析的な指数境界を整数 `n` に直接比較できる形へ変換する。 | |
| -/ | |
| lemma pow_bounds_iff_shifted_bounds (k n : Nat) : | |
| (phi ^ k ≤ logArg n ∧ logArg n < phi ^ (k + 1)) ↔ | |
| (phi ^ k / Real.sqrt 5 - (1 / 2 : Real) ≤ (n : Real) ∧ | |
| (n : Real) < phi ^ (k + 1) / Real.sqrt 5 - (1 / 2 : Real)) := by | |
| constructor | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have h1' : phi ^ k / Real.sqrt 5 ≤ (n : Real) + (1 / 2 : Real) := by | |
| refine (div_le_iff₀ sqrt5_pos).2 ?_ | |
| calc | |
| phi ^ k ≤ logArg n := h1 | |
| _ = Real.sqrt 5 * ((n : Real) + (1 / 2 : Real)) := rfl | |
| _ = ((n : Real) + (1 / 2 : Real)) * Real.sqrt 5 := by ring | |
| linarith | |
| · have h2' : (n : Real) + (1 / 2 : Real) < phi ^ (k + 1) / Real.sqrt 5 := by | |
| refine (lt_div_iff₀ sqrt5_pos).2 ?_ | |
| calc | |
| ((n : Real) + (1 / 2 : Real)) * Real.sqrt 5 = logArg n := by | |
| simp only [one_div, logArg, mul_comm] | |
| _ < phi ^ (k + 1) := h2 | |
| linarith | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have h1' : phi ^ k / Real.sqrt 5 ≤ (n : Real) + (1 / 2 : Real) := by linarith | |
| have h1'' : phi ^ k ≤ ((n : Real) + (1 / 2 : Real)) * Real.sqrt 5 := | |
| (div_le_iff₀ sqrt5_pos).1 h1' | |
| calc | |
| phi ^ k ≤ ((n : Real) + (1 / 2 : Real)) * Real.sqrt 5 := h1'' | |
| _ = logArg n := by simp only [one_div, logArg, mul_comm] | |
| · have h2' : (n : Real) + (1 / 2 : Real) < phi ^ (k + 1) / Real.sqrt 5 := by linarith | |
| have h2'' : ((n : Real) + (1 / 2 : Real)) * Real.sqrt 5 < phi ^ (k + 1) := | |
| (lt_div_iff₀ sqrt5_pos).1 h2' | |
| calc | |
| logArg n = ((n : Real) + (1 / 2 : Real)) * Real.sqrt 5 := by | |
| simp only [logArg, one_div, mul_comm] | |
| _ < phi ^ (k + 1) := h2'' | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: 平行移動境界とフィボナッチ区間条件は同値である。 | |
| 内容: `fib_binet_lower/upper` を `k` と `k+1` に適用し、 | |
| `Nat` と `Real` のキャストを介して `fib k ≤ n < fib (k+1)` に読み替える。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 解析的不等式から最終的な離散条件(フィボナッチ区間)へ接続する。 | |
| -/ | |
| lemma shifted_bounds_iff_fib_bounds (k n : Nat) : | |
| (phi ^ k / Real.sqrt 5 - (1 / 2 : Real) ≤ (n : Real) ∧ | |
| (n : Real) < phi ^ (k + 1) / Real.sqrt 5 - (1 / 2 : Real)) ↔ | |
| (fib k ≤ n ∧ n < fib (k + 1)) := by | |
| constructor | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have hk_up : (fib k : Real) < phi ^ k / Real.sqrt 5 + (1 / 2 : Real) := fib_binet_upper k | |
| have hk_lt : (fib k : Real) < (n : Real) + 1 := by linarith | |
| have hk_lt' : (fib k : Real) < ((n + 1 : Nat) : Real) := by | |
| simpa only [Nat.cast_add, Nat.cast_one] using hk_lt | |
| have hk_nat : fib k < n + 1 := by exact_mod_cast hk_lt' | |
| exact Nat.lt_succ_iff.mp hk_nat | |
| · have hk1_low : | |
| phi ^ (k + 1) / Real.sqrt 5 - (1 / 2 : Real) < (fib (k + 1) : Real) := | |
| fib_binet_lower (k + 1) | |
| have hM_lt : (n : Real) < (fib (k + 1) : Real) := lt_trans h2 hk1_low | |
| exact_mod_cast hM_lt | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have hk_low : phi ^ k / Real.sqrt 5 - (1 / 2 : Real) < (fib k : Real) := fib_binet_lower k | |
| have hk_le : (fib k : Real) ≤ (n : Real) := by exact_mod_cast h1 | |
| exact le_of_lt (lt_of_lt_of_le hk_low hk_le) | |
| · have h2' : n + 1 ≤ fib (k + 1) := Nat.succ_le_of_lt h2 | |
| have h2'' : ((n + 1 : Nat) : Real) ≤ (fib (k + 1) : Real) := by | |
| exact_mod_cast h2' | |
| have hk1_up : | |
| (fib (k + 1) : Real) < phi ^ (k + 1) / Real.sqrt 5 + (1 / 2 : Real) := | |
| fib_binet_upper (k + 1) | |
| have hplus : ((n + 1 : Nat) : Real) < phi ^ (k + 1) / Real.sqrt 5 + (1 / 2 : Real) := | |
| lt_of_le_of_lt h2'' hk1_up | |
| have hplus' : (n : Real) + 1 < phi ^ (k + 1) / Real.sqrt 5 + (1 / 2 : Real) := by | |
| simpa only [one_div, Nat.cast_add, Nat.cast_one] using hplus | |
| linarith | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `k = floor(log_φ(√5(n+1/2)))` と `fib k ≤ n < fib (k+1)` は同値である。 | |
| 内容: `floor_logPhi_iff` から始め、`logPhi_bounds_iff_pow_bounds`、 | |
| `pow_bounds_iff_shifted_bounds`、`shifted_bounds_iff_fib_bounds` を順に合成する。 | |
| 証明: 式変形で示す。 | |
| 役割: 本セクションの目標同値連鎖を一本の定理として確定する。 | |
| -/ | |
| theorem floor_logPhi_iff_fib_bounds (k n : Nat) : | |
| (k : Int) = Int.floor (logPhi (logArg n)) ↔ | |
| (fib k ≤ n ∧ n < fib (k + 1)) := by | |
| calc | |
| (k : Int) = Int.floor (logPhi (logArg n)) ↔ | |
| ((k : Real) ≤ logPhi (logArg n) ∧ logPhi (logArg n) < (k + 1 : Real)) := | |
| floor_logPhi_iff k n | |
| _ ↔ (phi ^ k ≤ logArg n ∧ logArg n < phi ^ (k + 1)) := | |
| logPhi_bounds_iff_pow_bounds k n | |
| _ ↔ (phi ^ k / Real.sqrt 5 - (1 / 2 : Real) ≤ (n : Real) ∧ | |
| (n : Real) < phi ^ (k + 1) / Real.sqrt 5 - (1 / 2 : Real)) := | |
| pow_bounds_iff_shifted_bounds k n | |
| _ ↔ (fib k ≤ n ∧ n < fib (k + 1)) := | |
| shifted_bounds_iff_fib_bounds k n | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `k = floor(log_φ(n+1/2) + log_φ(√5))` と | |
| `fib k ≤ n < fib (k+1)` は同値である。 | |
| 内容: `log_φ(√5*(n+1/2)) = log_φ(n+1/2) + log_φ(√5)` を | |
| `Real.logb_mul` で示し、`floor_logPhi_iff_fib_bounds` に帰着する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 主定理をユーザ指定の和の対数形で利用できるようにする。 | |
| -/ | |
| theorem floor_logPhi_add_sqrt5_iff_fib_bounds (k n : Nat) : | |
| (k : Int) = Int.floor (logPhi ((n : Real) + (1 / 2 : Real)) + logPhi (Real.sqrt 5)) ↔ | |
| (fib k ≤ n ∧ n < fib (k + 1)) := by | |
| have hn_pos : (0 : Real) < (n : Real) + (1 / 2 : Real) := by | |
| have hn0 : (0 : Real) ≤ (n : Real) := by positivity | |
| linarith | |
| have hn_ne : ((n : Real) + (1 / 2 : Real)) ≠ 0 := ne_of_gt hn_pos | |
| have hsqrt5_ne : (Real.sqrt 5) ≠ 0 := ne_of_gt sqrt5_pos | |
| have hlog : | |
| logPhi (logArg n) = | |
| logPhi ((n : Real) + (1 / 2 : Real)) + logPhi (Real.sqrt 5) := by | |
| unfold logPhi logArg | |
| calc | |
| Real.logb phi (Real.sqrt 5 * ((n : Real) + (1 / 2 : Real))) = | |
| Real.logb phi (Real.sqrt 5) + Real.logb phi ((n : Real) + (1 / 2 : Real)) := by | |
| simpa only [one_div] using | |
| (Real.logb_mul (b := phi) (x := Real.sqrt 5) (y := (n : Real) + (1 / 2 : Real)) | |
| hsqrt5_ne hn_ne) | |
| _ = | |
| Real.logb phi ((n : Real) + (1 / 2 : Real)) + Real.logb phi (Real.sqrt 5) := by | |
| ac_rfl | |
| simpa only [one_div, hlog] using (floor_logPhi_iff_fib_bounds (k := k) (n := n)) | |
| /-- | |
| 入力/前提: m : Nat。 | |
| 主張: `phi^(m+1)` は `fib (m+3)` より真に小さい。 | |
| 内容: `phi < 2` と `fib (m+1) > 0` から | |
| `phi*fib(m+1) < 2*fib(m+1)` を得て、`fib m` を加える。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `n < phi^(m+1) < fib(m+3)` の鎖を直接作る補助補題。 | |
| -/ | |
| lemma phi_pow_succ_lt_fib_add_three (m : Nat) : | |
| phi ^ (m + 1) < (fib (m + 3) : Real) := by | |
| have hphi_lt_two : phi < 2 := by | |
| simpa only [phi] using Real.goldenRatio_lt_two | |
| have hfib_nat_pos : 0 < fib (m + 1) := by | |
| exact (Nat.fib_pos).2 (Nat.succ_pos m) | |
| have hfib_pos : (0 : Real) < (fib (m + 1) : Real) := by | |
| exact_mod_cast hfib_nat_pos | |
| have hmul : | |
| phi * (fib (m + 1) : Real) < (2 : Real) * (fib (m + 1) : Real) := by | |
| nlinarith [hphi_lt_two, hfib_pos] | |
| calc | |
| phi ^ (m + 1) = phi * (fib (m + 1) : Real) + (fib m : Real) := by | |
| simpa only [phi] using (Real.goldenRatio_mul_fib_succ_add_fib m).symm | |
| _ < (2 : Real) * (fib (m + 1) : Real) + (fib m : Real) := by | |
| linarith | |
| _ = (fib (m + 1) : Real) + (fib (m + 1) : Real) + (fib m : Real) := by ring | |
| _ = (fib (m + 1) : Real) + (fib (m + 2) : Real) := by | |
| norm_num [Nat.fib_add_two, Nat.cast_add, add_assoc, add_comm, add_left_comm] | |
| _ = (fib (m + 3) : Real) := by | |
| norm_num [Nat.fib_add_two, Nat.cast_add, add_assoc, add_comm, add_left_comm] | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `n < fib (floor(log_φ n) + 3)` が成り立つ。 | |
| 内容: `m = floor(log_φ n)` として `log_φ n < m+1` から `n < phi^(m+1)` を得て、 | |
| `phi_pow_succ_lt_fib_add_three` で `phi^(m+1) < fib(m+3)` に移して結論する。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `n` に対する単純な `fib` 上界指標を `floor(log_φ n)` で与える。 | |
| -/ | |
| theorem lt_fib_floor_logPhi_add_three (n : Nat) : | |
| n < fib (Nat.floor (logPhi (n : Real)) + 3) := by | |
| by_cases hn : n = 0 | |
| · subst hn | |
| norm_num [logPhi] | |
| · let m : Nat := Nat.floor (logPhi (n : Real)) | |
| have hn_pos : (0 : Real) < (n : Real) := by exact_mod_cast Nat.pos_of_ne_zero hn | |
| have hlog_lt : logPhi (n : Real) < (m + 1 : Real) := by | |
| simpa only using (Nat.lt_floor_add_one (logPhi (n : Real))) | |
| have hn_lt_pow' : (n : Real) < phi ^ ((m : Real) + 1) := | |
| (Real.logb_lt_iff_lt_rpow one_lt_phi hn_pos).1 hlog_lt | |
| have hn_lt_pow : (n : Real) < phi ^ (m + 1) := by | |
| rw [← Real.rpow_natCast] | |
| simpa only [Nat.cast_add, Nat.cast_one] using hn_lt_pow' | |
| have hpow_lt_fib : phi ^ (m + 1) < (fib (m + 3) : Real) := | |
| phi_pow_succ_lt_fib_add_three m | |
| have hn_lt_fib_real : (n : Real) < (fib (m + 3) : Real) := | |
| lt_trans hn_lt_pow hpow_lt_fib | |
| have htarget : (n : Real) < (fib (Nat.floor (logPhi (n : Real)) + 3) : Real) := by | |
| simpa only [Nat.cast_lt] using hn_lt_fib_real | |
| exact_mod_cast htarget | |
| end | |
| end Fib |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name = "divapprox2" | |
| version = "0.1.0" | |
| keywords = ["math"] | |
| defaultTargets = ["Fib", "Mwf", "Divapprox2"] | |
| [leanOptions] | |
| pp.unicode.fun = true # pretty-prints `fun a ↦ b` | |
| autoImplicit = false | |
| relaxedAutoImplicit = false | |
| weak.linter.mathlibStandardSet = true | |
| maxSynthPendingDepth = 3 | |
| [[require]] | |
| name = "mathlib" | |
| scope = "leanprover-community" | |
| [[lean_lib]] | |
| name = "Fib" | |
| [[lean_lib]] | |
| name = "Mwf" | |
| [[lean_lib]] | |
| name = "Divapprox2" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| leanprover/lean4:v4.29.0-rc1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /- | |
| # Max Weighted Floor (MWF) コア部証明 | |
| ## 証明の内容 | |
| ### 共通の前提 | |
| - `0 < N`, `0 < M` を満たす整数 `N, M` (自然数ではなく整数として定義) | |
| - 整数 `A, B, C, D, R, S` | |
| - `mwf(N, M, A, B, C, D) = max { A*x + B*⌊(C*x + D)/M⌋ | 0 ≤ x < N }` | |
| --- | |
| ### 初期化 | |
| ``` | |
| mwf(N, M, A, B, C, D) | |
| = max( B*⌊D/M⌋, 0 + mwf(N, M, A, B, C, D) ) | |
| ``` | |
| * 以下は、 `max(R, S + mwf(N, M, A, B, C, D))` の形で議論を進める。 | |
| * 正規化と場合分けの両方で `R, S` は任意の整数として扱える。 | |
| * 正規化と場合分けを通じて `mwf` の引数が書き換わる際に `R, S` も同様に書き換えることで、 `max(R, S + mwf(...))` の形を保つ。 | |
| * 正規化と場合分けの過程を高々(log2(M)+1)回繰り返すことで、 | |
| `case Y = 0` の場合分けに到達するため、 | |
| 任意の `R, S, N, M, A, B, C, D` に対して | |
| `max(R, S + mwf(N, M, A, B, C, D))` を計算できる。 | |
| --- | |
| ### 正規化 | |
| ``` | |
| max(R, S + mwf(N, M, A, B, C, D)) | |
| = max( R, (S + B*⌊D/M⌋) + mwf(N, M, (A + B*⌊C/M⌋), B, (C mod M), (D mod M)) ) | |
| ``` | |
| --- | |
| ### 場合分け | |
| ここでは上の正規化を済ませた状態 `0 ≤ C, D < M` を仮定し,`Y = ⌊(C*(N-1) + D)/M⌋` とする。 | |
| ``` | |
| max(R, S + mwf(N, M, A, B, C, D)) | |
| = { | |
| case Y = 0 => | |
| max(R, S, S + max(0, A*(N-1))) | |
| case Y > 0, A ≥ 0 => | |
| max( max(R, S + A*(N-1) + B*Y), | |
| S + mwf(Y, C, B, A, M, (M-D-1)) ) | |
| case Y > 0, A < 0 => | |
| max( max(R, S, (S+A+B) + mwf(Y, C, B, A, M, (M-D-1)) ) | |
| } | |
| ``` | |
| -/ | |
| import Mathlib.Data.Int.Basic | |
| import Mathlib.Data.Int.Lemmas | |
| import Mathlib.Data.Int.Fib.Basic | |
| import Mathlib.Data.Finset.Basic | |
| import Mathlib.Data.Nat.Fib.Zeckendorf | |
| import Mathlib.Tactic | |
| import Fib | |
| namespace MWF | |
| /-- | |
| 目的: 整数の床除算を `Int.ediv` で表す。 | |
| 定義: `⌊t/M⌋` を `t / M` と定義。 | |
| 入力/前提: t M : Int、_hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 以後の床値計算の基底。 | |
| -/ | |
| @[simp] | |
| def zfloorDiv (t M : Int) (_hM : 0 < M) : Int := | |
| t / M | |
| /-- | |
| 目的: 整数の剰余を `Int.emod` で表す。 | |
| 定義: `t % M` を返す薄いラッパ。 | |
| 入力/前提: t M : Int、_hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 正規化で `C,D` を `mod M` に落とす基底。 | |
| -/ | |
| @[simp] | |
| def zfloorMod (t M : Int) (_hM : 0 < M) : Int := | |
| t % M | |
| /-- | |
| 目的: MWF の点評価関数を定義する。 | |
| 定義: `A*x + B*⌊(C*x + D)/M⌋` を返す。 | |
| 入力/前提: A B C D M x : Int、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 最大化対象そのもの。 | |
| -/ | |
| @[simp] | |
| def obj (A B C D M x : Int) (hM : 0 < M) : Int := | |
| A * x + B * zfloorDiv (C * x + D) M hM | |
| /-- | |
| 目的: 3項最大を定義する。 | |
| 定義: `max (max a b) c`。 | |
| 入力/前提: a b c : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 場合分け結果の可読化。 | |
| -/ | |
| @[simp] | |
| def max3 (a b c : Int) : Int := max (max a b) c | |
| /-- | |
| 目的: 4項最大を定義する。 | |
| 定義: `max3` を使った入れ子 `max`。 | |
| 入力/前提: a b c d : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 分岐後の式整理を簡潔化。 | |
| -/ | |
| @[simp] | |
| def max4 (a b c d : Int) : Int := max (max3 a b c) d | |
| /-- | |
| 目的: 走査区間 `0 ≤ x < N` を有限集合で表す。 | |
| 定義: `Icc 0 (N-1)` を採用。 | |
| 入力/前提: N : Int、_hN : 0 < N、0 : Int。 | |
| 出力: 型 `Finset Int` の値を返す。 | |
| 役割: `mwf` を Finset 最大値として扱う土台。 | |
| -/ | |
| @[simp] | |
| def dom (N : Int) (_hN : 0 < N) : Finset Int := Finset.Icc (0 : Int) (N - 1) | |
| /-- | |
| 目的: 走査区間 `L ≤ x < R` を有限集合で表す。 | |
| 定義: `Icc L (R-1)` を採用。 | |
| 入力/前提: L R : Int、_hLR : L < R、L : Int。 | |
| 出力: 型 `Finset Int` の値を返す。 | |
| 役割: `mwf` を Finset 最大値として扱う土台。 | |
| -/ | |
| @[simp] | |
| def domLr (L R : Int) (_hLR : L < R) : Finset Int := Finset.Icc (L : Int) (R - 1) | |
| /-- | |
| 目的: 目的関数の像集合を作る。 | |
| 定義: `dom` 上で `obj` を `image`。 | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Finset Int` の値を返す。 | |
| 役割: `mwf` 定義の直接入力。 | |
| -/ | |
| @[simp] | |
| def img (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : Finset Int := | |
| (dom N hN).image (fun x => obj A B C D M x hM) | |
| /-- | |
| 目的: 目的関数の像集合を作る。 | |
| 定義: `domLr` 上で `obj` を `image`。 | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 出力: 型 `Finset Int` の値を返す。 | |
| 役割: `mwfLr` 定義の直接入力。 | |
| -/ | |
| @[simp] | |
| def imgLr (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : Finset Int := | |
| (domLr L R hLR).image (fun x => obj A B C D M x hM) | |
| /-- | |
| 入力/前提: N : Int、hN : 0 < N。 | |
| 主張: `0<N` なら `dom` は非空。 | |
| 内容: `0 ∈ Icc 0 (N-1)` を構成。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `max'` 利用条件を満たす。 | |
| -/ | |
| lemma dom_nonempty {N : Int} (hN : 0 < N) : (dom N hN).Nonempty := by | |
| refine Exists.intro 0 ?_ | |
| exact Finset.mem_Icc.mpr (And.intro le_rfl (sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN))) | |
| /-- | |
| 入力/前提: L R : Int、hLR : L < R。 | |
| 主張: `L<R` なら `domLr` は非空。 | |
| 内容: `L ∈ Icc L (R-1)` を構成。 | |
| 証明: 式変形で示す。 | |
| 役割: `max'` 利用条件を満たす。 | |
| -/ | |
| lemma domLr_nonempty {L R : Int} (hLR : L < R) : (domLr L R hLR).Nonempty := by | |
| refine Exists.intro L ?_ | |
| have hL : L ≤ R - 1 := by | |
| nlinarith [hLR] | |
| exact Finset.mem_Icc.mpr (And.intro le_rfl hL) | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `0<N` なら `img` も非空。 | |
| 内容: `dom_nonempty` を像へ持ち上げる。 | |
| 証明: 場合分けで示す。 | |
| 役割: `mwf` の `max'` 定義を正当化。 | |
| -/ | |
| lemma img_nonempty {N M A B C D : Int} (hN : 0 < N) (hM : 0 < M) : | |
| (img N M A B C D hN hM).Nonempty := by | |
| cases dom_nonempty hN with | |
| | intro x hx => | |
| refine Exists.intro (obj A B C D M x hM) ?_ | |
| exact Finset.mem_image.mpr (Exists.intro x (And.intro hx rfl)) | |
| /-- | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 主張: `L<R` なら `imgLr` も非空。 | |
| 内容: `domLr_nonempty` を像へ持ち上げる。 | |
| 証明: 場合分けで示す。 | |
| 役割: `mwfLr` の `max'` 定義を正当化。 | |
| -/ | |
| lemma imgLr_nonempty {L R M A B C D : Int} (hLR : L < R) (hM : 0 < M) : | |
| (imgLr L R M A B C D hLR hM).Nonempty := by | |
| cases domLr_nonempty hLR with | |
| | intro x hx => | |
| refine Exists.intro (obj A B C D M x hM) ?_ | |
| exact Finset.mem_image.mpr (Exists.intro x (And.intro hx rfl)) | |
| /-- | |
| 目的: 問題値 `mwf` を定義する。 | |
| 定義: `img` の最大値 `max'` を返す。 | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 全証明で保存・変形する中心量。 | |
| -/ | |
| @[simp] | |
| def mwf (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : Int := | |
| let s := img N M A B C D hN hM | |
| s.max' (img_nonempty (N := N) (M := M) (A := A) (B := B) (C := C) (D := D) hN hM) | |
| /-- | |
| 目的: 問題値 `mwfLr` を定義する。 | |
| 定義: `imgLr` の最大値 `max'` を返す。 | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 全証明で保存・変形する中心量。 | |
| -/ | |
| @[simp] | |
| def mwfLr (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : Int := | |
| let s := imgLr L R M A B C D hLR hM | |
| s.max' (imgLr_nonempty (L := L) (R := R) (M := M) (A := A) (B := B) (C := C) (D := D) hLR hM) | |
| /-- | |
| 目的: `mwfLr` の最大値を達成する点集合を定義する。 | |
| 定義: `domLr` を `obj = mwfLr` で `filter` する。 | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 出力: 型 `Finset Int` の値を返す。 | |
| 役割: 最小 `argmax` を `min'` で取り出す基底。 | |
| -/ | |
| def mwfLrArgDom (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : Finset Int := | |
| (domLr L R hLR).filter (fun x => obj A B C D M x hM = mwfLr L R M A B C D hLR hM) | |
| /-- | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 主張: `mwfLrArgDom` は非空。 | |
| 内容: `mwfLr` は像 `imgLr` の `max'` なので、達成点が必ず存在する。 | |
| 証明: `Finset.max'_mem` と `Finset.mem_image` で達成点を取り出し、`filter` へ戻す。 | |
| 役割: `mwfLrArgmax` の `min'` 利用条件を満たす。 | |
| -/ | |
| lemma mwfLrArgDom_nonempty | |
| (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : | |
| (mwfLrArgDom L R M A B C D hLR hM).Nonempty := by | |
| have hmaxMem : mwfLr L R M A B C D hLR hM ∈ imgLr L R M A B C D hLR hM := by | |
| unfold mwfLr | |
| simpa only [imgLr, obj, zfloorDiv, domLr, Finset.mem_image, Finset.mem_Icc, | |
| Order.le_sub_one_iff] using | |
| (Finset.max'_mem (imgLr L R M A B C D hLR hM) | |
| (imgLr_nonempty (L := L) (R := R) (M := M) (A := A) (B := B) (C := C) (D := D) hLR hM)) | |
| rcases Finset.mem_image.mp hmaxMem with ⟨x, hxDom, hxEq⟩ | |
| refine ⟨x, ?_⟩ | |
| exact Finset.mem_filter.mpr ⟨hxDom, hxEq⟩ | |
| /-- | |
| 目的: `mwfLr` の最小 `argmax` を定義する。 | |
| 定義: `mwfLrArgDom` の `min'` を返す。 | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `max` と同時に `argmax`(同値時は最小)を得るための本体。 | |
| -/ | |
| def mwfLrArgmax (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : Int := | |
| (mwfLrArgDom L R M A B C D hLR hM).min' (mwfLrArgDom_nonempty L R M A B C D hLR hM) | |
| /-- | |
| 目的: 区間版 MWF の最大値と `argmax` を同時に返す型を定義する。 | |
| フィールド: `max`, `argmax`。 | |
| 不変条件: `argmax` は `[L, R)` 内で `max` を達成する最小添字。 | |
| 役割: `mwfLrWithArgmax` の返り値型。 | |
| -/ | |
| structure MwfLrArgResult where | |
| max : Int | |
| argmax : Int | |
| deriving Repr, DecidableEq | |
| /-- | |
| 目的: `max_{L≤x<R}(A*x + B*⌊(C*x + D)/M⌋)` と最小 `argmax` を同時に返す。 | |
| 定義: `mwfLr` と `mwfLrArgmax` を束ねる。 | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 出力: 型 `MwfLrArgResult` の値を返す。 | |
| 役割: 区間最大値と最小達成点の同時計算インターフェース。 | |
| -/ | |
| def mwfLrWithArgmax | |
| (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : MwfLrArgResult := | |
| { max := mwfLr L R M A B C D hLR hM | |
| argmax := mwfLrArgmax L R M A B C D hLR hM } | |
| /-- | |
| 目的: 正規化後の `A'` を与える。 | |
| 定義: `A + B*⌊C/M⌋`。 | |
| 入力/前提: A B C M : Int、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `C` の商成分を線形項へ吸収。 | |
| -/ | |
| @[simp] | |
| def normA (A B C M : Int) (hM : 0 < M) : Int := A + B * zfloorDiv C M hM | |
| /-- | |
| 目的: 正規化後の `S'` を与える。 | |
| 定義: `S + B*⌊D/M⌋`。 | |
| 入力/前提: S B D M : Int、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 定数項のずれを外側に移す。 | |
| -/ | |
| @[simp] | |
| def normS (S B D M : Int) (hM : 0 < M) : Int := S + B * zfloorDiv D M hM | |
| /-- | |
| 目的: 正規化後の `C'` を与える。 | |
| 定義: `C % M`。 | |
| 入力/前提: C M : Int、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `0 ≤ C' < M` の世界へ遷移。 | |
| -/ | |
| @[simp] | |
| def normC (C M : Int) (hM : 0 < M) : Int := zfloorMod C M hM | |
| /-- | |
| 目的: 正規化後の `D'` を与える。 | |
| 定義: `D % M`。 | |
| 入力/前提: D M : Int、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `0 ≤ D' < M` の世界へ遷移。 | |
| -/ | |
| @[simp] | |
| def normD (D M : Int) (hM : 0 < M) : Int := zfloorMod D M hM | |
| /-- | |
| 目的: 各 `x` に対応する商 `y` を定義する。 | |
| 定義: `⌊(C*x + D)/M⌋`。 | |
| 入力/前提: M C D : Int、hM : 0 < M、x : Int。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x` 側と再帰 `y` 側の橋渡し。 | |
| -/ | |
| @[simp] | |
| def yOf (M C D : Int) (hM : 0 < M) (x : Int) : Int := | |
| zfloorDiv (C * x + D) M hM | |
| /-- | |
| 目的: 右端 `x=N-1` での商 `Y` を定義する。 | |
| 定義: `yOf` を `N-1` で評価。 | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 分岐 (`Y=0` / `Y>0`) の判定量。 | |
| -/ | |
| @[simp] | |
| def Yn1 (N M C D : Int) (hN : 0 < N) (hM : 0 < M) : Int := | |
| let hx0 : 0 ≤ N - 1 := by | |
| have h1 : (1 : Int) ≤ N := (Int.lt_iff_add_one_le).1 hN | |
| exact sub_nonneg.mpr h1 | |
| let hxn : N - 1 < N := by | |
| simp only [sub_eq_add_neg, Int.reduceNeg, add_lt_iff_neg_left, Int.neg_neg_iff_pos, zero_lt_one] | |
| yOf (M := M) (C := C) (D := D) (x := N - 1) hM | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 正規化仮定下で `Yn1 ≥ 0`。 | |
| 内容: 分子非負と `M>0` から `ediv_nonneg`。 | |
| 証明: 式変形で示す。 | |
| 役割: `step_reduce` の分岐前提を供給。 | |
| -/ | |
| lemma Y_nonneg | |
| (N M C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) : | |
| 0 ≤ Yn1 N M C D hN hM := by | |
| unfold Yn1 yOf zfloorDiv | |
| have hNm1 : 0 ≤ N - 1 := sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN) | |
| have hNum : 0 ≤ C * (N - 1) + D := by | |
| nlinarith [mul_nonneg hC0 hNm1, hD0] | |
| exact Int.ediv_nonneg hNum (le_of_lt hM) | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `Yn1>0` なら `C>0`。 | |
| 内容: `C=0` とすると `Yn1=0` になる矛盾。 | |
| 証明: 反証法・式変形・既存補題の書き換えで示す。 | |
| 役割: 逆写像式の除数正性を保証。 | |
| -/ | |
| lemma hCpos_of_Y_ge_one (N M C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) | |
| (hDM : D < M) (hYp : 0 < Yn1 N M C D hN hM) : 0 < C := by | |
| by_contra hCnot | |
| have hCeq : C = 0 := le_antisymm (le_of_not_gt hCnot) hC0 | |
| have hdiv0 : D / M = 0 := Int.ediv_eq_zero_of_lt_abs hD0 (by simpa only [abs_of_pos hM] using hDM) | |
| have hY0 : Yn1 N M C D hN hM = 0 := by | |
| simp only [Yn1, yOf, zfloorDiv, hCeq, zero_mul, zero_add, hdiv0] | |
| rw [hY0] at hYp | |
| exact (lt_irrefl (0 : Int)) hYp | |
| /-- | |
| 目的: 商 `y` を与える左端代表 `x` を定義する。 | |
| 定義: `y=0` は `0`、それ以外は明示式。 | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `A<0` 側再帰の下界構成。 | |
| -/ | |
| @[simp] | |
| def iy_left | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (_hC0 : 0 ≤ C) (_hD0 : 0 ≤ D) (_hCM : C < M) (_hDM : D < M) | |
| (_hy0 : 0 ≤ y) (_hyN : y ≤ Yn1 N M C D hN hM) : | |
| Int := | |
| if hY0 : y = 0 then 0 | |
| else | |
| -- editorial.md「記法補助(区間端点)」の議論より,`y ≠ 0` なら区間は少なくとも 1 段上がるので `Yn1 ≥ 1` を得る方針。 | |
| let hY1 : 1 ≤ Yn1 N M C D hN hM := by | |
| have hypos0 : 0 < y := lt_of_le_of_ne _hy0 (fun hyzero => hY0 hyzero.symm) | |
| have hypos1 : (1 : Int) ≤ y := (Int.lt_iff_add_one_le).1 hypos0 | |
| exact le_trans hypos1 _hyN | |
| let hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM _hC0 _hD0 _hDM hY1 | |
| zfloorDiv (M * y + C - D - 1) C hCpos | |
| /-- | |
| 目的: 商 `y` を与える右端代表 `x` を定義する。 | |
| 定義: `y=Yn1` は `N-1`、それ以外は明示式。 | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `A≥0` 側再帰の上界構成。 | |
| -/ | |
| @[simp] | |
| def iy_right | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (_hC0 : 0 ≤ C) (_hD0 : 0 ≤ D) (_hCM : C < M) (_hDM : D < M) | |
| (_hy0 : 0 ≤ y) (_hyN : y ≤ Yn1 N M C D hN hM) : | |
| Int := | |
| if hYn1 : y = Yn1 N M C D hN hM then N - 1 | |
| else | |
| -- editorial.md「記法補助(区間端点)」に従い,`y ≠ Yn1` の場合も商が 1 以上になることを示して `Yn1 ≥ 1` を得る。 | |
| let hY1 : 1 ≤ Yn1 N M C D hN hM := by | |
| have hy_lt : y < Yn1 N M C D hN hM := lt_of_le_of_ne _hyN (fun hy => hYn1 hy) | |
| have hpos : 0 < Yn1 N M C D hN hM := lt_of_le_of_lt _hy0 hy_lt | |
| exact (Int.lt_iff_add_one_le).1 hpos | |
| let hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM _hC0 _hD0 _hDM hY1 | |
| zfloorDiv (M * y + M - D - 1) C hCpos | |
| /-- | |
| 目的: 非正規化状態を表す構造体。 | |
| フィールド: `max(r, s+mwf(...))` の係数一式を保持。 | |
| 不変条件: 必要な制約はフィールドの仮定として保持する。 | |
| 役割: 1ステップ同値の対象。 | |
| -/ | |
| structure St where | |
| (r s n m a b c d : Int) (hn : 0 < n) (hm : 0 < m) | |
| /-- | |
| 目的: 正規化済み状態を表す構造体。 | |
| フィールド: `0 ≤ c,d < m` の証明付き状態。 | |
| 不変条件: 必要な制約はフィールドの仮定として保持する。 | |
| 役割: 場合分け定理の前提を型で保持。 | |
| -/ | |
| structure StNorm where | |
| (r s n m a b c d : Int) (hn : 0 < n) (hm : 0 < m) | |
| (hC0 : 0 ≤ c) (hD0 : 0 ≤ d) (hCM : c < m) (hDM : d < m) | |
| /-- | |
| 目的: 2状態の評価式同値を定義する。 | |
| 定義: `max(r, s+mwf)` の等式。 | |
| 入力/前提: S T : St。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 遷移の正しさ記述に使う述語。 | |
| -/ | |
| @[simp] | |
| def StEq (S T : St) : Prop := | |
| max S.r (S.s + mwf S.n S.m S.a S.b S.c S.d S.hn S.hm) = | |
| max T.r (T.s + mwf T.n T.m T.a T.b T.c T.d T.hn T.hm) | |
| /-- | |
| 目的: 状態正規化ステップを定義する。 | |
| 定義: `normA/normS/normC/normD` で更新。 | |
| 入力/前提: U : St。 | |
| 出力: 型 `StNorm` の値を返す。 | |
| 役割: 再帰前の標準形への写像。 | |
| -/ | |
| @[simp] | |
| def step_normalize (U : St) : StNorm := | |
| let a := normA U.a U.b U.c U.m U.hm | |
| let b := U.b | |
| let c := normC U.c U.m U.hm | |
| let d := normD U.d U.m U.hm | |
| let s := normS U.s U.b U.d U.m U.hm | |
| StNorm.mk U.r s U.n U.m a b c d U.hn U.hm | |
| (Int.emod_nonneg _ (ne_of_gt U.hm)) | |
| (Int.emod_nonneg _ (ne_of_gt U.hm)) | |
| (Int.emod_lt_of_pos _ U.hm) | |
| (Int.emod_lt_of_pos _ U.hm) | |
| /-- | |
| 目的: 正規化状態の分岐量 `Y` を読む。 | |
| 定義: `Yn1 U.n U.m U.c U.d`。 | |
| 入力/前提: U : StNorm。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `step_reduce` 分岐条件の抽象化。 | |
| -/ | |
| @[simp] | |
| def stnorm_y (U : StNorm) : Int := | |
| Yn1 U.n U.m U.c U.d U.hn U.hm | |
| /-- | |
| 目的: 状態 `St` の `mwf` 成分を読む。 | |
| 定義: フィールドを `mwf` に渡す。 | |
| 入力/前提: U : St。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 状態同値式を簡潔化。 | |
| -/ | |
| @[simp] | |
| def st_mwf (U : St) : Int := | |
| mwf U.n U.m U.a U.b U.c U.d U.hn U.hm | |
| /-- | |
| 目的: 状態 `StNorm` の `mwf` 成分を読む。 | |
| 定義: フィールドを `mwf` に渡す。 | |
| 入力/前提: U : StNorm。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 正規化後同値式を簡潔化。 | |
| -/ | |
| @[simp] | |
| def stnorm_mwf (U : StNorm) : Int := | |
| mwf U.n U.m U.a U.b U.c U.d U.hn U.hm | |
| /-- | |
| 目的: `Y=0` 分岐の遷移先を与える。 | |
| 定義: `r,s` を終端形 `(1,1,0,...)` に集約。 | |
| 入力/前提: U : StNorm、_hy0 : stnorm_y U = 0。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 停止ケースの具体状態。 | |
| -/ | |
| @[simp] | |
| def step_reduce_y0 (U : StNorm) (_hy0 : stnorm_y U = 0) : St := | |
| let r := max U.r U.s | |
| let r' := max r (U.s + U.a * (U.n - 1)) | |
| St.mk r' r' 1 1 0 0 0 0 (by decide) (by decide) | |
| /-- | |
| 目的: `Y>0 ∧ A≥0` 分岐の遷移先を与える。 | |
| 定義: 右端寄り評価で `r` を更新し引数を入替。 | |
| 入力/前提: U : StNorm、hYp : 0 < stnorm_y U、_hAnonneg : 0 ≤ U.a。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 正傾き再帰を状態遷移化。 | |
| -/ | |
| @[simp] | |
| def step_reduce_ypos_a_nonneg | |
| (U : StNorm) | |
| (hYp : 0 < stnorm_y U) | |
| (_hAnonneg : 0 ≤ U.a) : St := | |
| St.mk (max U.r (U.s + (U.a * (U.n - 1) + U.b * stnorm_y U))) U.s | |
| (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYp (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYp) | |
| /-- | |
| 目的: `Y>0 ∧ A<0` 分岐の遷移先を与える。 | |
| 定義: `s` に `A+B` を加えて引数を入替。 | |
| 入力/前提: U : StNorm、hYp : 0 < stnorm_y U、_hAneg : U.a < 0。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 負傾き再帰を状態遷移化。 | |
| -/ | |
| @[simp] | |
| def step_reduce_ypos_a_neg | |
| (U : StNorm) | |
| (hYp : 0 < stnorm_y U) | |
| (_hAneg : U.a < 0) : St := | |
| St.mk (max U.r U.s) (U.s + (U.a + U.b)) | |
| (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYp (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYp) | |
| /-- | |
| 目的: 正規化状態の分岐遷移を定義する。 | |
| 定義: `Y=0` と `A` の符号で3分岐。 | |
| 入力/前提: U : StNorm。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 再帰本体の単一関数化。 | |
| -/ | |
| @[simp] | |
| def step_reduce (U : StNorm) : St := | |
| let y := stnorm_y U | |
| if hy0 : y = 0 then | |
| step_reduce_y0 U hy0 | |
| else | |
| have hY0 : 0 ≤ y := Y_nonneg U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 | |
| have hYp : 0 < y := lt_of_le_of_ne hY0 (fun hyzero => hy0 hyzero.symm) | |
| if hAnonneg : 0 ≤ U.a then | |
| step_reduce_ypos_a_nonneg U hYp hAnonneg | |
| else | |
| step_reduce_ypos_a_neg U hYp (lt_of_not_ge hAnonneg) | |
| /-- | |
| 目的: 1ステップ遷移を定義する。 | |
| 定義: `step_normalize` の後に `step_reduce`。 | |
| 入力/前提: S : St。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 反復する基本演算。 | |
| -/ | |
| @[simp] | |
| def step (S : St) : St := | |
| step_reduce (step_normalize S) | |
| /-- | |
| 目的: `m` から得られる反復回数上界(`greatestFibIter m - 1`)。 | |
| 定義: `greatestFibIter` から 1 引いた上界として停止到達回数に適用する | |
| (`m>0` では `Nat.greatestFib m - 1` と同値)。 | |
| 入力/前提: m : Nat。 | |
| 出力: 型 `Nat` の値を返す。 | |
| 役割: tex 側の「高々 `g(m)-1` 回で停止」と整合する上界を与える。 | |
| -/ | |
| def stepBoundOfM (m : Nat) : Nat := | |
| Fib.greatestFibIter m - 1 | |
| /-- | |
| 目的: `mwf_iter_aux` は `mwf` 計算の反復補助関数を定義する。 | |
| 定義: `step` を高々 `fuel` 回だけ回し、`c=0` に到達した時点の `r` を返す。 | |
| 入力/前提: `fuel : Nat`、`U : St`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `mwf_iter` の反復本体。 | |
| -/ | |
| @[simp] | |
| def mwf_iter_aux : Nat → St → Int | |
| | 0, U => U.r | |
| | k + 1, U => | |
| let V := step U | |
| if _ : U.c = 0 then V.r else mwf_iter_aux k V | |
| /-- | |
| 目的: `mwf_iter` は `mwf` を反復で計算する実装を定義する。 | |
| 定義: 初期状態を作り、`stepBoundOfM (Int.toNat M)` 回 `mwf_iter_aux` を適用する。 | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 反復実装の入口(`mwf_iter_correct` の対象)。 | |
| -/ | |
| def mwf_iter (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : Int := | |
| let U : St := St.mk (B * zfloorDiv D M hM) 0 N M A B C D hN hM | |
| mwf_iter_aux (stepBoundOfM (Int.toNat M)) U | |
| /-- | |
| 目的: 区間版 `mwfLr_iter` を反復計算として定義する。 | |
| 定義: 置換 `x = l + t` と商・剰余分解で `mwf_iter` に還元し定数項を加える。 | |
| 入力/前提: l r m a b c d : Int、hLR : l < r、hM : 0 < m。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 区間版実装の計算定義。 | |
| -/ | |
| def mwfLr_iter (l r m a b c d : Int) (hLR : l < r) (hM : 0 < m) : Int := by | |
| have hN : 0 < r - l := by nlinarith [hLR] | |
| let n : Int := r - l | |
| let q : Int := zfloorDiv (c * l + d) m hM | |
| let d' : Int := zfloorMod (c * l + d) m hM | |
| exact a * l + b * q + mwf_iter n m a b c d' hN hM | |
| -- #eval mwfLr_iter 0 10 7 3 2 5 4 (by decide) (by decide) -- 41 | |
| -- #eval mwf_iter 1000000000 102334155 (-433494437) 701408733 63245986 31415926 | |
| -- (by decide) (by decide) -- 215327987 | |
| -- #eval stepBoundOfM 102334155 -- 40 | |
| -- #eval Nat.fib 40 -- 102334155 | |
| -- #eval Nat.fib 41 -- 165580141 | |
| -- #eval mwf_iter_aux 50 | |
| -- (St.mk 0 0 1000000000 102334155 (-433494437) 701408733 63245986 31415926 | |
| -- (by decide) (by decide)) -- 215327987 | |
| noncomputable section | |
| /-- | |
| 入力/前提: N M A B C D x : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 各点の目的値は `mwf` 以下。 | |
| 内容: `obj x` が `img` の元であることを使う。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 上界評価の基本補題。 | |
| -/ | |
| lemma obj_le_mwf (N M A B C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hx : x ∈ dom N hN) : | |
| obj A B C D M x hM ≤ mwf N M A B C D hN hM := by | |
| unfold mwf | |
| dsimp only [obj, zfloorDiv, img, dom, Lean.Elab.WF.paramLet] | |
| exact Finset.le_max' (s := img N M A B C D hN hM) (x := obj A B C D M x hM) | |
| (Finset.mem_image.mpr (Exists.intro x (And.intro hx rfl))) | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `C=0` なら `Yn1=0`。 | |
| 内容: `0≤D<M` から `D/M=0` を適用。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 退化ケースの停止判定。 | |
| -/ | |
| lemma Y_eq_zero_of_C_eq_zero | |
| (N M C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) | |
| (hD0 : 0 ≤ D) (hDM : D < M) | |
| (hC : C = 0) : | |
| Yn1 N M C D hN hM = 0 := by | |
| have hdiv0 : D / M = 0 := Int.ediv_eq_zero_of_lt_abs hD0 (by simpa only [abs_of_pos hM] using hDM) | |
| simp only [Yn1, yOf, zfloorDiv, hC, zero_mul, zero_add, hdiv0] | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `N=1` なら `Yn1=0`。 | |
| 内容: `N-1=0` へ還元して `D/M=0` を適用。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 最小サイズケースの停止判定。 | |
| -/ | |
| lemma Y_eq_zero_of_N_eq_one | |
| (N M C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) (hD0 : 0 ≤ D) (hDM : D < M) | |
| (hN1 : N = 1) : | |
| Yn1 N M C D hN hM = 0 := by | |
| subst hN1 | |
| have hdiv0 : D / M = 0 := Int.ediv_eq_zero_of_lt_abs hD0 (by simpa only [abs_of_pos hM] using hDM) | |
| simp only [Yn1, yOf, zfloorDiv, sub_self, mul_zero, zero_add, hdiv0] | |
| /-! | |
| ## 補題 | |
| -/ | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `dom` 上では `yOf ≥ 0`。 | |
| 内容: 分子非負と `M>0` から示す。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 商範囲 `0..Y` の下限側。 | |
| -/ | |
| lemma yOf_nonneg | |
| (N M C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (_hCM : C < M) (_hDM : D < M) : | |
| ∀ x : dom N hN, | |
| 0 ≤ yOf M C D hM x := by | |
| intro x | |
| have hx0 : 0 ≤ (x : Int) := (Finset.mem_Icc.mp x.property).1 | |
| have hNum : 0 ≤ C * (x : Int) + D := by | |
| nlinarith [mul_nonneg hC0 hx0, hD0] | |
| simpa only [yOf, zfloorDiv, dom, ge_iff_le] using Int.ediv_nonneg hNum (le_of_lt hM) | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `dom` 上では `yOf ≤ Yn1`。 | |
| 内容: `x ≤ N-1` の単調性と除算評価で示す。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 商範囲 `0..Y` の上限側。 | |
| -/ | |
| lemma yOf_le_Yn1 | |
| (N M C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (_hD0 : 0 ≤ D) (_hCM : C < M) (_hDM : D < M) : | |
| ∀ x : dom N hN, | |
| yOf M C D hM x ≤ Yn1 N M C D hN hM := by | |
| intro x | |
| have hxle : (x : Int) ≤ N - 1 := (Finset.mem_Icc.mp x.property).2 | |
| have hMulLe : C * (x : Int) ≤ C * (N - 1) := mul_le_mul_of_nonneg_left hxle hC0 | |
| have hNumLe : C * (x : Int) + D ≤ C * (N - 1) + D := by nlinarith | |
| have hdivLe : (C * (x : Int) + D) / M ≤ (C * (N - 1) + D) / M := Int.ediv_le_ediv hM hNumLe | |
| simpa only [yOf, zfloorDiv, dom, Yn1, ge_iff_le] using hdivLe | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 右端 `x=N-1` の目的値を明示化。 | |
| 内容: `obj` 展開で `A*(N-1)+B*Yn1`。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `A≥0` 分岐の端点評価。 | |
| -/ | |
| lemma obj_at_right (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| obj A B C D M (N - 1) hM = A * (N - 1) + B * Yn1 N M C D hN hM := by | |
| simp only [obj, zfloorDiv, Yn1, yOf] | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `dom` の任意要素で `obj ≤ mwf`。 | |
| 内容: `Finset.le_max'` を直接適用。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 逆写像点からの上界取得。 | |
| -/ | |
| lemma obj_le_mwf_of_mem (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| {y : Int} (hy : y ∈ dom N hN) : | |
| obj A B C D M y hM ≤ mwf N M A B C D hN hM := by | |
| exact obj_le_mwf N M A B C D y hN hM hy | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `dom` 上の床除算値は `0..Yn1` に入る。 | |
| 内容: 非負性と右端比較で上下界を同時に構成。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 値域制御の基礎。 | |
| -/ | |
| lemma floorDiv_range_bounds (N M C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (_hCM : C < M) (_hDM : D < M) : | |
| ∀ x ∈ dom N hN, | |
| 0 ≤ zfloorDiv (C * x + D) M hM ∧ | |
| zfloorDiv (C * x + D) M hM ≤ Yn1 N M C D hN hM := by | |
| intro x hx | |
| constructor | |
| · have h1 := yOf_nonneg N M C D hN hM hC0 hD0 _hCM _hDM (Subtype.mk x hx) | |
| simpa only [zfloorDiv, ge_iff_le, yOf] using h1 | |
| · have h2 := yOf_le_Yn1 N M C D hN hM hC0 hD0 _hCM _hDM (Subtype.mk x hx) | |
| simpa only [zfloorDiv, Yn1, yOf, ge_iff_le] using h2 | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 任意の `0≤y≤Yn1` はある `x` で実現される。 | |
| 内容: しきい値集合の最小元を使って構成。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `y` 側再帰を `x` 側へ戻す鍵。 | |
| -/ | |
| lemma floorDiv_range_attain (N M C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (_hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) : | |
| let Y₀ := Yn1 N M C D hN hM; | |
| ∀ y, 0 ≤ y ∧ y ≤ Y₀ → ∃ x ∈ dom N hN, zfloorDiv (C * x + D) M hM = y := by | |
| dsimp only [Yn1, yOf, zfloorDiv, dom, Lean.Elab.WF.paramLet] | |
| intro y hy | |
| rcases hy with ⟨hy0, hyY⟩ | |
| by_cases hyTop : y = Yn1 N M C D hN hM | |
| · refine ⟨N - 1, ?_, ?_⟩ | |
| · exact Finset.mem_Icc.mpr ⟨sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN), le_rfl⟩ | |
| · simp only [hyTop, Yn1, yOf, zfloorDiv] | |
| · have hmem : | |
| iy_right N M C D y hN hM _hC0 hD0 hCM hDM hy0 hyY ∈ dom N hN := by | |
| have hy_lt : y < Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy' => hyTop hy') | |
| have hYpos : 0 < Yn1 N M C D hN hM := lt_of_le_of_lt hy0 hy_lt | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM _hC0 hD0 hDM hY1 | |
| have hy1 : y + 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hy_lt | |
| have hy1' : y + 1 ≤ (C * (N - 1) + D) / M := by | |
| simpa only [Order.add_one_le_iff, Yn1, yOf, zfloorDiv] using hy1 | |
| have hmul : (y + 1) * M ≤ C * (N - 1) + D := | |
| (Int.le_ediv_iff_mul_le hM).1 hy1' | |
| have hnum_nonneg : 0 ≤ M * y + M - D - 1 := by | |
| nlinarith [mul_nonneg (le_of_lt hM) hy0, hDM] | |
| have hnum_lt_CN : M * y + M - D - 1 < C * N := by | |
| have hnum_le : M * y + M - D - 1 ≤ C * (N - 1) - 1 := by | |
| nlinarith [hmul] | |
| have hlt' : C * (N - 1) - 1 < C * (N - 1) + C := by | |
| nlinarith [hCpos] | |
| have hlt'' : C * (N - 1) + C = C * N := by ring | |
| exact lt_of_le_of_lt hnum_le (by simpa only [Order.sub_one_lt_iff, hlt''] using hlt') | |
| have hx0 : | |
| 0 ≤ zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| simpa only [zfloorDiv] using Int.ediv_nonneg hnum_nonneg (le_of_lt hCpos) | |
| have hxN : | |
| zfloorDiv (M * y + M - D - 1) C hCpos ≤ N - 1 := by | |
| have hlt : | |
| M * y + M - D - 1 < (N - 1) * C + C := by | |
| calc | |
| M * y + M - D - 1 < C * N := hnum_lt_CN | |
| _ = (N - 1) * C + C := by ring | |
| exact (Int.ediv_le_iff_le_mul hCpos).2 hlt | |
| have hmem' : | |
| zfloorDiv (M * y + M - D - 1) C hCpos ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨hx0, hxN⟩ | |
| have hYn1' : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Yn1, yOf, zfloorDiv] using hyTop | |
| simpa only [dom, iy_right, Yn1, yOf, zfloorDiv, hYn1', ↓reduceDIte, Finset.mem_Icc, | |
| Order.le_sub_one_iff] using hmem' | |
| have heq : | |
| zfloorDiv (C * (iy_right N M C D y hN hM _hC0 hD0 hCM hDM hy0 hyY) + D) M hM = y := by | |
| have hy_lt : y < Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy' => hyTop hy') | |
| have hYpos : 0 < Yn1 N M C D hN hM := lt_of_le_of_lt hy0 hy_lt | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM _hC0 hD0 hDM hY1 | |
| have hneq : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Yn1, yOf, zfloorDiv] using hyTop | |
| have hiy : | |
| iy_right N M C D y hN hM _hC0 hD0 hCM hDM hy0 hyY | |
| = zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| simp only [iy_right, Yn1, yOf, zfloorDiv, hneq, ↓reduceDIte] | |
| rw [hiy] | |
| unfold zfloorDiv | |
| let a : Int := M * y + M - D - 1 | |
| have hxle : a / C ≤ a / C := le_rfl | |
| have hlt_ax : a < (a / C) * C + C := (Int.ediv_le_iff_le_mul hCpos).1 hxle | |
| have hmul_up : (a / C) * C ≤ a := (Int.le_ediv_iff_mul_le hCpos).1 le_rfl | |
| have hnum_up : C * (a / C) + D ≤ M * y + M - 1 := by | |
| nlinarith [hmul_up] | |
| have hupper : | |
| (C * (a / C) + D) / M ≤ y := by | |
| have hdiv_le : (C * (a / C) + D) / M ≤ (M * y + M - 1) / M := | |
| Int.ediv_le_ediv hM hnum_up | |
| have hM1_nonneg : 0 ≤ M - 1 := by nlinarith [hM] | |
| have hM1_lt : M - 1 < M := by nlinarith [hM] | |
| have hM1_div : (M - 1) / M = 0 := | |
| Int.ediv_eq_zero_of_lt_abs hM1_nonneg (by | |
| rw [abs_of_pos hM] | |
| exact hM1_lt) | |
| have hrhs : (M * y + M - 1) / M = y := by | |
| calc | |
| (M * y + M - 1) / M = ((M - 1) + y * M) / M := by ring_nf | |
| _ = (M - 1) / M + y := by | |
| simpa only [mul_comm, add_comm] using | |
| (Int.add_mul_ediv_right (M - 1) y (ne_of_gt hM)) | |
| _ = y := by simp only [hM1_div, zero_add] | |
| exact le_trans hdiv_le (by simp only [hrhs, le_refl]) | |
| have hmul_low : y * M ≤ C * (a / C) + D := by | |
| have hlt1 : M * y + M - D - 1 < C * (a / C) + C := by | |
| simpa only [a, add_comm, Order.sub_one_lt_iff, tsub_le_iff_right, | |
| add_left_comm, mul_comm] using hlt_ax | |
| have hCMle : C ≤ M := le_of_lt hCM | |
| nlinarith [hlt1, hCMle] | |
| have hlower : y ≤ (C * (a / C) + D) / M := | |
| (Int.le_ediv_iff_mul_le hM).2 (by | |
| simpa only [mul_comm] using hmul_low) | |
| exact le_antisymm hupper hlower | |
| refine ⟨iy_right N M C D y hN hM _hC0 hD0 hCM hDM hy0 hyY, hmem, ?_⟩ | |
| exact heq | |
| /-! | |
| ## 初期化 | |
| `x=0` は常に許されるため、`mwf` は `obj ... 0 = B*⌊D/M⌋` 以上。 | |
| よって | |
| `mwf = max(B*⌊D/M⌋, 0 + mwf)` | |
| が成立。 | |
| -/ | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 初期化等式 `mwf = max(B⌊D/M⌋, 0+mwf)`。 | |
| 内容: `x=0` が常に候補である事実を使う。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 状態法の開始点。 | |
| -/ | |
| theorem step_init_equiv | |
| (N M A B C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) : | |
| mwf N M A B C D hN hM | |
| = max (B * zfloorDiv D M hM) (0 + mwf N M A B C D hN hM) := by | |
| have hx0 : (0 : Int) ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr (And.intro le_rfl (sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN))) | |
| have hbase_obj : obj A B C D M 0 hM ≤ mwf N M A B C D hN hM := | |
| obj_le_mwf N M A B C D 0 hN hM hx0 | |
| have hbase : B * zfloorDiv D M hM ≤ mwf N M A B C D hN hM := by | |
| simpa only [zfloorDiv, mwf, img, obj, dom, mul_zero, zero_add] using hbase_obj | |
| have hmax_le : | |
| max (B * zfloorDiv D M hM) (0 + mwf N M A B C D hN hM) ≤ mwf N M A B C D hN hM := by | |
| refine max_le hbase ?_ | |
| simp only [mwf, img, obj, zfloorDiv, dom, zero_add, le_refl] | |
| have hle_max : mwf N M A B C D hN hM ≤ max (B * zfloorDiv D M hM) (0 + mwf N M A B C D hN hM) := | |
| by | |
| calc | |
| mwf N M A B C D hN hM = 0 + mwf N M A B C D hN hM := by simp only [mwf, img, obj, zfloorDiv, | |
| dom, zero_add] | |
| _ ≤ max (B * zfloorDiv D M hM) (0 + mwf N M A B C D hN hM) := le_max_right _ _ | |
| exact le_antisymm hle_max hmax_le | |
| /-! | |
| ## 正規化 | |
| `C = M*⌊C/M⌋ + (C % M)`, `D = M*⌊D/M⌋ + (D % M)` と | |
| `M>0` の下での | |
| `⌊(t + k*M)/M⌋ = ⌊t/M⌋ + k` | |
| を用いると、各 `x` で | |
| ⌊(C*x + D)/M⌋ | |
| = ⌊C/M⌋*x + ⌊((C%M)*x + (D%M))/M⌋ + ⌊D/M⌋ | |
| よって | |
| Ax + B⌊(Cx+D)/M⌋ | |
| = (A + B⌊C/M⌋)x + B⌊((C%M)x + (D%M))/M⌋ + B⌊D/M⌋ | |
| 最大を取って外側の `max R` を付ければ主張。 | |
| -/ | |
| /-- | |
| 入力/前提: A B C D M S x : Int、hM : 0 < M。 | |
| 主張: `S+obj` は正規化後の `S'+obj'` と一致。 | |
| 内容: `C,D` の商剰余分解を式変形。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 点ごとの正規化同値の核。 | |
| -/ | |
| lemma normalize_obj_eq (A B C D M S x : Int) (hM : 0 < M) : | |
| S + obj A B C D M x hM = | |
| (normS S B D M hM) + obj (normA A B C M hM) B (normC C M hM) (normD D M hM) M x hM := by | |
| have hM0 : M ≠ 0 := ne_of_gt hM | |
| have hdecomp : C * x + D = (C % M * x + D % M) + ((C / M) * x + D / M) * M := by | |
| calc | |
| C * x + D = (C % M + M * (C / M)) * x + (D % M + M * (D / M)) := by | |
| rw [Int.emod_add_mul_ediv C M, Int.emod_add_mul_ediv D M] | |
| _ = (C % M * x + D % M) + ((C / M) * x + D / M) * M := by ring | |
| have hdiv : (C * x + D) / M = (C % M * x + D % M) / M + ((C / M) * x + D / M) := by | |
| rw [hdecomp] | |
| simpa only [mul_comm, add_comm, add_left_comm, add_assoc] using | |
| (Int.add_mul_ediv_right (C % M * x + D % M) ((C / M) * x + D / M) hM0) | |
| unfold obj normS normA normC normD zfloorDiv zfloorMod | |
| rw [hdiv] | |
| ring | |
| /-- | |
| 入力/前提: R S N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 外側 `max R` 付きでも正規化前後で値が等しい。 | |
| 内容: `normalize_obj_eq` を最大値へ持ち上げる。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 状態正規化の正当化。 | |
| -/ | |
| theorem normalize_max | |
| (R S N M A B C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) : | |
| max R (S + mwf N M A B C D hN hM) | |
| = | |
| max R ((normS S B D M hM) + | |
| mwf N M (normA A B C M hM) B (normC C M hM) (normD D M hM) hN hM) := by | |
| let m0 := mwf N M A B C D hN hM | |
| let m1 := mwf N M (normA A B C M hM) B (normC C M hM) (normD D M hM) hN hM | |
| have hm1_mem : | |
| m1 ∈ img N M (normA A B C M hM) B (normC C M hM) (normD D M hM) hN hM := by | |
| dsimp only [normA, zfloorDiv, normC, zfloorMod, normD, img, obj, dom, mwf, m1] | |
| exact Finset.max'_mem _ _ | |
| rcases Finset.mem_image.mp hm1_mem with ⟨x1, hx1, hx1eq⟩ | |
| have hm0_mem : m0 ∈ img N M A B C D hN hM := by | |
| dsimp only [img, obj, zfloorDiv, dom, mwf, m0] | |
| exact Finset.max'_mem _ _ | |
| rcases Finset.mem_image.mp hm0_mem with ⟨x0, hx0, hx0eq⟩ | |
| have hobj1_le_m0 : obj A B C D M x1 hM ≤ m0 := by | |
| simpa only [obj, zfloorDiv, mwf, img, dom] using obj_le_mwf N M A B C D x1 hN hM hx1 | |
| have hobj0_le_m1 : | |
| obj (normA A B C M hM) B (normC C M hM) (normD D M hM) M x0 hM ≤ m1 := by | |
| simpa only [obj, normA, zfloorDiv, normC, zfloorMod, normD, mwf, img, dom] using | |
| obj_le_mwf N M (normA A B C M hM) B (normC C M hM) (normD D M hM) x0 hN hM hx0 | |
| have hle1 : normS S B D M hM + m1 ≤ S + m0 := by | |
| calc | |
| normS S B D M hM + m1 | |
| = normS S B D M hM + | |
| obj (normA A B C M hM) B (normC C M hM) (normD D M hM) M x1 hM := by | |
| rw [← hx1eq] | |
| _ = S + obj A B C D M x1 hM := by | |
| symm | |
| simpa only [obj, zfloorDiv, normS, normA, normC, zfloorMod, normD] using | |
| normalize_obj_eq A B C D M S x1 hM | |
| _ ≤ S + m0 := by | |
| simpa only [obj, zfloorDiv, add_comm, add_le_add_iff_left] using | |
| add_le_add_left hobj1_le_m0 S | |
| have hle2 : S + m0 ≤ normS S B D M hM + m1 := by | |
| calc | |
| S + m0 = S + obj A B C D M x0 hM := by rw [← hx0eq] | |
| _ = normS S B D M hM + | |
| obj (normA A B C M hM) B (normC C M hM) (normD D M hM) M x0 hM := by | |
| simpa only [obj, zfloorDiv, normS, normA, normC, zfloorMod, normD] using | |
| normalize_obj_eq A B C D M S x0 hM | |
| _ ≤ normS S B D M hM + m1 := by | |
| simpa only [normS, zfloorDiv, obj, normA, normC, zfloorMod, normD, add_comm, add_assoc, | |
| add_le_add_iff_left] using add_le_add_left hobj0_le_m1 (normS S B D M hM) | |
| have hmwf_eq : S + m0 = normS S B D M hM + m1 := le_antisymm hle2 hle1 | |
| exact congrArg (fun t => max R t) hmwf_eq | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `Yn1=0` なら `mwf = max 0 (A*(N-1))`。 | |
| 内容: 商項が全点で 0 になることを利用。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 再帰停止時の閉形式。 | |
| -/ | |
| theorem mwf_yn1_zero (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hY0 : (Yn1 N M C D hN hM) = 0) : | |
| mwf N M A B C D hN hM | |
| = | |
| max 0 (A * (N - 1)) := by | |
| have hDdiv0 : zfloorDiv D M hM = 0 := by | |
| unfold zfloorDiv | |
| exact Int.ediv_eq_zero_of_lt_abs hD0 (by simpa only [abs_of_pos hM] using hDM) | |
| have hx0 : (0 : Int) ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr (And.intro le_rfl (sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN))) | |
| have h0le : 0 ≤ mwf N M A B C D hN hM := by | |
| have hobj0_le := obj_le_mwf N M A B C D 0 hN hM hx0 | |
| have hDdiv0' : D / M = 0 := by simpa only [zfloorDiv] using hDdiv0 | |
| have hobj0 : obj A B C D M 0 hM = 0 := by | |
| calc | |
| obj A B C D M 0 hM = A * 0 + B * (D / M) := by | |
| simp only [obj, mul_zero, zfloorDiv, zero_add] | |
| _ = A * 0 + B * 0 := by rw [hDdiv0'] | |
| _ = 0 := by simp only [mul_zero, add_zero] | |
| rw [hobj0] at hobj0_le | |
| exact hobj0_le | |
| have hxN1 : (N - 1 : Int) ∈ dom N hN := by | |
| refine Finset.mem_Icc.mpr ?_ | |
| constructor | |
| · exact sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN) | |
| · exact le_rfl | |
| have hRight : A * (N - 1) ≤ mwf N M A B C D hN hM := by | |
| have hobjR_le := obj_le_mwf N M A B C D (N - 1) hN hM hxN1 | |
| have hobjR : obj A B C D M (N - 1) hM = A * (N - 1) := by | |
| calc | |
| obj A B C D M (N - 1) hM = A * (N - 1) + B * Yn1 N M C D hN hM := by | |
| exact obj_at_right N M A B C D hN hM | |
| _ = A * (N - 1) + B * 0 := by rw [hY0] | |
| _ = A * (N - 1) := by simp only [mul_zero, add_zero] | |
| calc | |
| A * (N - 1) = obj A B C D M (N - 1) hM := hobjR.symm | |
| _ ≤ mwf N M A B C D hN hM := hobjR_le | |
| have hLower : max 0 (A * (N - 1)) ≤ mwf N M A B C D hN hM := | |
| max_le h0le hRight | |
| have hUpper : mwf N M A B C D hN hM ≤ max 0 (A * (N - 1)) := by | |
| change | |
| (img N M A B C D hN hM).max' | |
| (img_nonempty (N := N) (M := M) (A := A) (B := B) (C := C) (D := D) hN hM) | |
| ≤ max 0 (A * (N - 1)) | |
| refine Finset.max'_le (s := img N M A B C D hN hM) | |
| (H := img_nonempty (N := N) (M := M) (A := A) (B := B) (C := C) (D := D) hN hM) | |
| (x := max 0 (A * (N - 1))) ?_ | |
| intro z hz | |
| rcases Finset.mem_image.mp hz with ⟨x, hxdom, rfl⟩ | |
| have hnonneg : | |
| 0 ≤ zfloorDiv (C * x + D) M hM := by | |
| have htmp := yOf_nonneg N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxdom) | |
| simpa only [zfloorDiv, ge_iff_le, yOf] using htmp | |
| have hleY : | |
| zfloorDiv (C * x + D) M hM ≤ Yn1 N M C D hN hM := by | |
| have htmp := yOf_le_Yn1 N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxdom) | |
| simpa only [zfloorDiv, Yn1, yOf, ge_iff_le] using htmp | |
| have hle0 : zfloorDiv (C * x + D) M hM ≤ 0 := by | |
| have hleY' := hleY | |
| rw [hY0] at hleY' | |
| exact hleY' | |
| have hdiv0x : zfloorDiv (C * x + D) M hM = 0 := by | |
| exact le_antisymm hle0 hnonneg | |
| have hx0' : 0 ≤ x := (Finset.mem_Icc.mp hxdom).1 | |
| have hxN : x ≤ N - 1 := (Finset.mem_Icc.mp hxdom).2 | |
| have hAx : | |
| A * x ≤ max 0 (A * (N - 1)) := by | |
| by_cases hAnonneg : 0 ≤ A | |
| · exact le_trans (mul_le_mul_of_nonneg_left hxN hAnonneg) (le_max_right 0 (A * (N - 1))) | |
| · have hmul0 : A * x ≤ 0 := mul_nonpos_of_nonpos_of_nonneg (le_of_not_ge hAnonneg) hx0' | |
| exact le_trans hmul0 (le_max_left 0 (A * (N - 1))) | |
| have hobjx : obj A B C D M x hM = A * x := by | |
| calc | |
| obj A B C D M x hM = A * x + B * zfloorDiv (C * x + D) M hM := by | |
| simp only [obj, zfloorDiv] | |
| _ = A * x + B * 0 := by rw [hdiv0x] | |
| _ = A * x := by simp only [mul_zero, add_zero] | |
| calc | |
| obj A B C D M x hM = A * x := hobjx | |
| _ ≤ max 0 (A * (N - 1)) := hAx | |
| exact le_antisymm hUpper hLower | |
| /-- | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `iy_right` は常に `dom` に属する。 | |
| 内容: 端点分岐と除算不等式で区間内を示す。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `iy_right` を評価点として合法化。 | |
| -/ | |
| lemma iy_right_mem_dom | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hy0 : 0 ≤ y) (hyY : y ≤ Yn1 N M C D hN hM) : | |
| iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY ∈ dom N hN := by | |
| by_cases hYn1 : y = Yn1 N M C D hN hM | |
| · have hxN1 : (N - 1 : Int) ∈ dom N hN := by | |
| refine Finset.mem_Icc.mpr ?_ | |
| constructor | |
| · exact sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN) | |
| · exact le_rfl | |
| simpa only [dom, iy_right, hYn1, Yn1, yOf, zfloorDiv, ↓reduceDIte, Finset.mem_Icc, | |
| Int.sub_nonneg, le_refl, and_true, ge_iff_le] using hxN1 | |
| · have hy_lt : y < Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy => hYn1 hy) | |
| have hYpos : 0 < Yn1 N M C D hN hM := lt_of_le_of_lt hy0 hy_lt | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hY1 | |
| have hy1 : y + 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hy_lt | |
| have hy1' : y + 1 ≤ (C * (N - 1) + D) / M := by | |
| simpa only [Order.add_one_le_iff, Yn1, yOf, zfloorDiv] using hy1 | |
| have hmul : (y + 1) * M ≤ C * (N - 1) + D := | |
| (Int.le_ediv_iff_mul_le hM).1 hy1' | |
| have hnum_nonneg : 0 ≤ M * y + M - D - 1 := by | |
| nlinarith [mul_nonneg (le_of_lt hM) hy0, hDM] | |
| have hnum_lt_CN : M * y + M - D - 1 < C * N := by | |
| have hnum_le : M * y + M - D - 1 ≤ C * (N - 1) - 1 := by | |
| nlinarith [hmul] | |
| have hlt' : C * (N - 1) - 1 < C * (N - 1) + C := by | |
| nlinarith [hCpos] | |
| have hlt'' : C * (N - 1) + C = C * N := by ring | |
| exact lt_of_le_of_lt hnum_le (by simpa only [Order.sub_one_lt_iff, hlt''] using hlt') | |
| have hx0 : | |
| 0 ≤ zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| simpa only [zfloorDiv] using Int.ediv_nonneg hnum_nonneg (le_of_lt hCpos) | |
| have hxN : | |
| zfloorDiv (M * y + M - D - 1) C hCpos ≤ N - 1 := by | |
| have hlt : | |
| M * y + M - D - 1 < (N - 1) * C + C := by | |
| calc | |
| M * y + M - D - 1 < C * N := hnum_lt_CN | |
| _ = (N - 1) * C + C := by ring | |
| exact (Int.ediv_le_iff_le_mul hCpos).2 hlt | |
| have hmem : | |
| zfloorDiv (M * y + M - D - 1) C hCpos ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨hx0, hxN⟩ | |
| have hYn1' : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Yn1, yOf, zfloorDiv] using hYn1 | |
| simpa only [dom, iy_right, Yn1, yOf, zfloorDiv, hYn1', ↓reduceDIte, Finset.mem_Icc, | |
| Order.le_sub_one_iff] using hmem | |
| /-- | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `y≠Yn1` なら `yOf (iy_right y) = y`。 | |
| 内容: `iy_right` の定義式と床除算境界を照合。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `A≥0` 再帰の値一致に必須。 | |
| -/ | |
| lemma yOf_iy_right | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hy0 : 0 ≤ y) (hyY : y ≤ Yn1 N M C D hN hM) | |
| (hy_ne : y ≠ Yn1 N M C D hN hM) : | |
| yOf M C D hM (iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY) | |
| = y := by | |
| have hy_lt : y < Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy => hy_ne hy) | |
| have hYpos : 0 < Yn1 N M C D hN hM := lt_of_le_of_lt hy0 hy_lt | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hY1 | |
| have hneq : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Yn1, yOf, zfloorDiv] using hy_ne | |
| have hiy : | |
| iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY | |
| = zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| simp only [iy_right, Yn1, yOf, zfloorDiv, hneq, ↓reduceDIte] | |
| rw [hiy] | |
| unfold yOf zfloorDiv | |
| let a : Int := M * y + M - D - 1 | |
| have hxle : a / C ≤ a / C := le_rfl | |
| have hlt_ax : a < (a / C) * C + C := (Int.ediv_le_iff_le_mul hCpos).1 hxle | |
| have hmul_up : (a / C) * C ≤ a := (Int.le_ediv_iff_mul_le hCpos).1 le_rfl | |
| have hnum_up : C * (a / C) + D ≤ M * y + M - 1 := by | |
| nlinarith [hmul_up] | |
| have hupper : | |
| (C * (a / C) + D) / M ≤ y := by | |
| have hdiv_le : (C * (a / C) + D) / M ≤ (M * y + M - 1) / M := | |
| Int.ediv_le_ediv hM hnum_up | |
| have hM1_nonneg : 0 ≤ M - 1 := by nlinarith [hM] | |
| have hM1_lt : M - 1 < M := by nlinarith [hM] | |
| have hM1_div : (M - 1) / M = 0 := | |
| Int.ediv_eq_zero_of_lt_abs hM1_nonneg (by | |
| rw [abs_of_pos hM] | |
| exact hM1_lt) | |
| have hrhs : (M * y + M - 1) / M = y := by | |
| calc | |
| (M * y + M - 1) / M = ((M - 1) + y * M) / M := by ring_nf | |
| _ = (M - 1) / M + y := by | |
| simpa only [mul_comm, add_comm] using (Int.add_mul_ediv_right (M - 1) y (ne_of_gt hM)) | |
| _ = y := by simp only [hM1_div, zero_add] | |
| exact le_trans hdiv_le (by simp only [hrhs, le_refl]) | |
| have hmul_low : y * M ≤ C * (a / C) + D := by | |
| have hlt1 : M * y + M - D - 1 < C * (a / C) + C := by | |
| simpa only [a, add_comm, Order.sub_one_lt_iff, tsub_le_iff_right, add_left_comm, | |
| mul_comm] using hlt_ax | |
| have hCMle : C ≤ M := le_of_lt hCM | |
| nlinarith [hlt1, hCMle] | |
| have hlower : y ≤ (C * (a / C) + D) / M := | |
| (Int.le_ediv_iff_mul_le hM).2 (by simpa only [mul_comm] using hmul_low) | |
| exact le_antisymm hupper hlower | |
| /-- | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `iy_left` は常に `dom` に属する。 | |
| 内容: 端点分岐と除算不等式で区間内を示す。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `iy_left` を評価点として合法化。 | |
| -/ | |
| lemma iy_left_mem_dom | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hy0 : 0 ≤ y) (hyY : y ≤ Yn1 N M C D hN hM) : | |
| iy_left N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY ∈ dom N hN := by | |
| by_cases hY0 : y = 0 | |
| · have hx0 : (0 : Int) ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr (And.intro le_rfl (sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN))) | |
| simpa only [dom, iy_left, hY0, ↓reduceDIte, Finset.mem_Icc, le_refl, Int.sub_nonneg, true_and, | |
| ge_iff_le] using hx0 | |
| · have hy_pos : 0 < y := lt_of_le_of_ne hy0 (fun hy => hY0 hy.symm) | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := by | |
| have hy1 : (1 : Int) ≤ y := (Int.lt_iff_add_one_le).1 hy_pos | |
| exact le_trans hy1 hyY | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hY1 | |
| have hy' : y ≤ (C * (N - 1) + D) / M := by | |
| simpa only [Yn1, yOf, zfloorDiv] using hyY | |
| have hmul : y * M ≤ C * (N - 1) + D := | |
| (Int.le_ediv_iff_mul_le hM).1 hy' | |
| have hnum_nonneg : 0 ≤ M * y + C - D - 1 := by | |
| nlinarith [mul_nonneg (le_of_lt hM) (le_of_lt hy_pos), hDM, hC0] | |
| have hnum_lt_CN : M * y + C - D - 1 < C * N := by | |
| have hnum_le : M * y + C - D - 1 ≤ C * (N - 1) + C - 1 := by | |
| nlinarith [hmul] | |
| have hlt' : C * (N - 1) + C - 1 < C * (N - 1) + C := by nlinarith | |
| have hCN : C * (N - 1) + C = C * N := by ring | |
| have hltCN : C * (N - 1) + C - 1 < C * N := by | |
| calc | |
| C * (N - 1) + C - 1 < C * (N - 1) + C := hlt' | |
| _ = C * N := hCN | |
| exact lt_of_le_of_lt hnum_le hltCN | |
| have hx0 : | |
| 0 ≤ zfloorDiv (M * y + C - D - 1) C hCpos := by | |
| simpa only [zfloorDiv] using Int.ediv_nonneg hnum_nonneg (le_of_lt hCpos) | |
| have hxN : | |
| zfloorDiv (M * y + C - D - 1) C hCpos ≤ N - 1 := by | |
| have hlt : | |
| M * y + C - D - 1 < (N - 1) * C + C := by | |
| calc | |
| M * y + C - D - 1 < C * N := hnum_lt_CN | |
| _ = (N - 1) * C + C := by ring | |
| exact (Int.ediv_le_iff_le_mul hCpos).2 hlt | |
| have hmem : | |
| zfloorDiv (M * y + C - D - 1) C hCpos ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨hx0, hxN⟩ | |
| simpa only [dom, iy_left, hY0, ↓reduceDIte, zfloorDiv, Finset.mem_Icc, | |
| Order.le_sub_one_iff] using hmem | |
| /-- | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `y≠0` なら `yOf (iy_left y) = y`。 | |
| 内容: `iy_left` の定義式と床除算境界を照合。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `A<0` 再帰の値一致に必須。 | |
| -/ | |
| lemma yOf_iy_left | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hy0 : 0 ≤ y) (hyY : y ≤ Yn1 N M C D hN hM) | |
| (hy_ne : y ≠ 0) : | |
| yOf M C D hM (iy_left N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY) | |
| = y := by | |
| have hy_pos : 0 < y := lt_of_le_of_ne hy0 (fun hy => hy_ne hy.symm) | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := by | |
| have hy1 : (1 : Int) ≤ y := (Int.lt_iff_add_one_le).1 hy_pos | |
| exact le_trans hy1 hyY | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hY1 | |
| have hiy : | |
| iy_left N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY | |
| = zfloorDiv (M * y + C - D - 1) C hCpos := by | |
| simp only [iy_left, hy_ne, ↓reduceDIte, zfloorDiv] | |
| rw [hiy] | |
| unfold yOf zfloorDiv | |
| let a : Int := M * y + C - D - 1 | |
| have hmul_up : (a / C) * C ≤ a := (Int.le_ediv_iff_mul_le hCpos).1 le_rfl | |
| have hnum_up : C * (a / C) + D ≤ M * y + C - 1 := by | |
| nlinarith [hmul_up] | |
| have hnum_up' : C * (a / C) + D ≤ M * y + M - 1 := by | |
| nlinarith [hnum_up, hCM] | |
| have hupper : | |
| (C * (a / C) + D) / M ≤ y := by | |
| have hdiv_le : (C * (a / C) + D) / M ≤ (M * y + M - 1) / M := | |
| Int.ediv_le_ediv hM hnum_up' | |
| have hM1_nonneg : 0 ≤ M - 1 := by nlinarith [hM] | |
| have hM1_lt : M - 1 < M := by nlinarith [hM] | |
| have hM1_div : (M - 1) / M = 0 := | |
| Int.ediv_eq_zero_of_lt_abs hM1_nonneg (by | |
| rw [abs_of_pos hM] | |
| exact hM1_lt) | |
| have hrhs : (M * y + M - 1) / M = y := by | |
| calc | |
| (M * y + M - 1) / M = ((M - 1) + y * M) / M := by ring_nf | |
| _ = (M - 1) / M + y := by | |
| simpa only [mul_comm, add_comm] using (Int.add_mul_ediv_right (M - 1) y (ne_of_gt hM)) | |
| _ = y := by simp only [hM1_div, zero_add] | |
| exact le_trans hdiv_le (by simp only [hrhs, le_refl]) | |
| have hlt_ax : a < (a / C) * C + C := (Int.ediv_le_iff_le_mul hCpos).1 le_rfl | |
| have hmul_low : y * M ≤ C * (a / C) + D := by | |
| have hlt1 : M * y + C - D - 1 < C * (a / C) + C := by | |
| simpa only [a, add_comm, Order.sub_one_lt_iff, tsub_le_iff_right, add_left_comm, | |
| add_le_add_iff_left, mul_comm] using hlt_ax | |
| have hlt2 : M * y < C * (a / C) + D + 1 := by nlinarith [hlt1] | |
| have hle2 : M * y ≤ C * (a / C) + D := (Int.lt_add_one_iff).1 hlt2 | |
| simpa only [mul_comm, ge_iff_le] using hle2 | |
| have hlower : y ≤ (C * (a / C) + D) / M := | |
| (Int.le_ediv_iff_mul_le hM).2 (by simpa only [mul_comm] using hmul_low) | |
| exact le_antisymm hupper hlower | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `Y>0 ∧ A≥0` の再帰式を与える。 | |
| 内容: 右端項と入替後 `mwf` の二項最大に分解。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 正傾き分岐の主定理。 | |
| -/ | |
| theorem mwf_yn1_pos_a_nonneg (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hYpos : 0 < Yn1 N M C D hN hM) (hAnonneg : A ≥ 0) : | |
| let YY := Yn1 N M C D hN hM | |
| let hCpos : 0 < C := | |
| hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hYpos | |
| mwf N M A B C D hN hM | |
| = | |
| max | |
| (A * (N - 1) + B * YY) | |
| (mwf YY C B A M (M - D - 1) hYpos hCpos) | |
| := by | |
| dsimp only [Yn1, yOf, zfloorDiv, mwf, img, obj, dom, Lean.Elab.WF.paramLet] | |
| let YY : Int := Yn1 N M C D hN hM | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hYpos | |
| have hRight_le : | |
| A * (N - 1) + B * YY ≤ mwf N M A B C D hN hM := by | |
| have hxN1 : (N - 1 : Int) ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN), le_rfl⟩ | |
| have hobj := obj_le_mwf N M A B C D (N - 1) hN hM hxN1 | |
| simpa only [Yn1, yOf, zfloorDiv, mwf, img, obj, dom, ge_iff_le] using | |
| (obj_at_right N M A B C D hN hM ▸ hobj) | |
| have hRec_le : | |
| mwf YY C B A M (M - D - 1) hYpos hCpos ≤ mwf N M A B C D hN hM := by | |
| unfold mwf | |
| dsimp only [img, obj, zfloorDiv, dom, Lean.Elab.WF.paramLet] | |
| refine Finset.max'_le | |
| (s := img YY C B A M (M - D - 1) hYpos hCpos) | |
| (H := img_nonempty | |
| (N := YY) (M := C) (A := B) (B := A) (C := M) (D := M - D - 1) | |
| hYpos hCpos) | |
| (x := mwf N M A B C D hN hM) ?_ | |
| intro z hz | |
| rcases Finset.mem_image.mp hz with ⟨y, hyDom, rfl⟩ | |
| have hy0 : 0 ≤ y := (Finset.mem_Icc.mp hyDom).1 | |
| have hyLePred : y ≤ YY - 1 := (Finset.mem_Icc.mp hyDom).2 | |
| have hy_lt : y < YY := by nlinarith | |
| have hy_leYY : y ≤ YY := le_of_lt hy_lt | |
| let x : Int := iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hy_leYY | |
| have hxDom : x ∈ dom N hN := iy_right_mem_dom N M C D y hN hM hC0 hD0 hCM hDM hy0 hy_leYY | |
| have hyOf : yOf M C D hM x = y := by | |
| have hne : y ≠ Yn1 N M C D hN hM := by simpa only [Yn1, yOf, zfloorDiv, ne_eq] using | |
| (ne_of_lt hy_lt) | |
| exact yOf_iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hy_leYY hne | |
| have hxDef : x = zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| have hneYY : y ≠ YY := ne_of_lt hy_lt | |
| have hne : y ≠ Yn1 N M C D hN hM := by simpa only [Yn1, yOf, zfloorDiv, ne_eq] using hneYY | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hneq' : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Yn1, yOf, zfloorDiv] using hne | |
| unfold x iy_right | |
| simp only [Yn1, yOf, zfloorDiv, hneq', ↓reduceDIte] | |
| have hyDiv : zfloorDiv (C * x + D) M hM = y := by simpa only [zfloorDiv, yOf] using hyOf | |
| have hObjEq : obj B A M (M - D - 1) C y hCpos = obj A B C D M x hM := by | |
| have harg : M * y + (M - D - 1) = M * y + M - D - 1 := by ring | |
| calc | |
| obj B A M (M - D - 1) C y hCpos | |
| = B * y + A * zfloorDiv (M * y + (M - D - 1)) C hCpos := by | |
| simp only [obj, zfloorDiv] | |
| _ = B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos := by rw [harg] | |
| _ = B * y + A * x := by rw [hxDef] | |
| _ = A * x + B * y := by ring | |
| _ = A * x + B * zfloorDiv (C * x + D) M hM := by rw [hyDiv] | |
| _ = obj A B C D M x hM := by simp only [zfloorDiv, obj] | |
| have hObjLe : obj A B C D M x hM ≤ mwf N M A B C D hN hM := | |
| obj_le_mwf_of_mem N M A B C D hN hM hxDom | |
| exact hObjEq.symm ▸ hObjLe | |
| have hMax_le : | |
| max (A * (N - 1) + B * YY) (mwf YY C B A M (M - D - 1) hYpos hCpos) | |
| ≤ mwf N M A B C D hN hM := max_le hRight_le hRec_le | |
| have hMwf_le : | |
| mwf N M A B C D hN hM | |
| ≤ max (A * (N - 1) + B * YY) (mwf YY C B A M (M - D - 1) hYpos hCpos) := by | |
| unfold mwf | |
| dsimp only [img, obj, zfloorDiv, dom, Lean.Elab.WF.paramLet] | |
| refine Finset.max'_le | |
| (s := img N M A B C D hN hM) | |
| (H := img_nonempty (N := N) (M := M) (A := A) (B := B) (C := C) (D := D) hN hM) | |
| (x := max (A * (N - 1) + B * YY) (mwf YY C B A M (M - D - 1) hYpos hCpos)) ?_ | |
| intro z hz | |
| rcases Finset.mem_image.mp hz with ⟨x, hxDom, rfl⟩ | |
| let y : Int := yOf M C D hM x | |
| have hy0 : 0 ≤ y := by | |
| have htmp := yOf_nonneg N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxDom) | |
| simpa only [yOf, zfloorDiv, ge_iff_le] using htmp | |
| have hyY : y ≤ YY := by | |
| have htmp := yOf_le_Yn1 N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxDom) | |
| simpa only [yOf, zfloorDiv, Yn1, ge_iff_le] using htmp | |
| by_cases hyTop : y = YY | |
| · have hxLe : x ≤ N - 1 := (Finset.mem_Icc.mp hxDom).2 | |
| have hyDiv : zfloorDiv (C * x + D) M hM = YY := by simpa only [zfloorDiv, yOf] using hyTop | |
| have hA_le : A * x ≤ A * (N - 1) := mul_le_mul_of_nonneg_left hxLe hAnonneg | |
| have hObj_le : obj A B C D M x hM ≤ A * (N - 1) + B * YY := by | |
| calc | |
| obj A B C D M x hM = A * x + B * zfloorDiv (C * x + D) M hM := by simp only [obj, | |
| zfloorDiv] | |
| _ = A * x + B * YY := by rw [hyDiv] | |
| _ ≤ A * (N - 1) + B * YY := by nlinarith [hA_le] | |
| exact le_trans hObj_le (le_max_left _ _) | |
| · have hy_lt : y < YY := lt_of_le_of_ne hyY (fun hy' => hyTop hy') | |
| have hyDomYY : y ∈ dom YY hYpos := by | |
| exact Finset.mem_Icc.mpr ⟨hy0, by nlinarith [hy_lt]⟩ | |
| have hRecObj : | |
| obj B A M (M - D - 1) C y hCpos ≤ mwf YY C B A M (M - D - 1) hYpos hCpos := | |
| obj_le_mwf_of_mem YY C B A M (M - D - 1) hYpos hCpos hyDomYY | |
| have hDiv : zfloorDiv (C * x + D) M hM = y := by rfl | |
| have hDivEq : (C * x + D) / M = y := by simpa only [zfloorDiv] using hDiv | |
| have hNum_up : C * x ≤ M * y + M - D - 1 := by | |
| have hdivLe : (C * x + D) / M ≤ y := le_of_eq hDivEq | |
| have hlt : C * x + D < y * M + M := (Int.ediv_le_iff_le_mul hM).1 hdivLe | |
| nlinarith | |
| have hXub : x ≤ zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| exact (Int.le_ediv_iff_mul_le hCpos).2 (by | |
| simpa only [mul_comm, Order.le_sub_one_iff] using hNum_up) | |
| have hAub : A * x ≤ A * zfloorDiv (M * y + M - D - 1) C hCpos := | |
| mul_le_mul_of_nonneg_left hXub hAnonneg | |
| have harg : M * y + (M - D - 1) = M * y + M - D - 1 := by ring | |
| have hObj2 : obj B A M (M - D - 1) C y hCpos = | |
| B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| calc | |
| obj B A M (M - D - 1) C y hCpos | |
| = B * y + A * zfloorDiv (M * y + (M - D - 1)) C hCpos := by simp only [obj, zfloorDiv] | |
| _ = B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos := by rw [harg] | |
| have hObj_le_rec : obj A B C D M x hM ≤ obj B A M (M - D - 1) C y hCpos := by | |
| calc | |
| obj A B C D M x hM = A * x + B * y := by simp only [obj, zfloorDiv, yOf, y] | |
| _ ≤ A * zfloorDiv (M * y + M - D - 1) C hCpos + B * y := by nlinarith [hAub] | |
| _ = B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos := by ring | |
| _ = obj B A M (M - D - 1) C y hCpos := hObj2.symm | |
| exact le_trans hObj_le_rec (le_trans hRecObj (le_max_right _ _)) | |
| exact le_antisymm hMwf_le hMax_le | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `Y>0 ∧ A<0` の再帰式を与える。 | |
| 内容: `0` と `(A+B)+`入替後 `mwf` の最大に分解。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 負傾き分岐の主定理。 | |
| -/ | |
| theorem mwf_yn1_pos_a_neg (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hYpos : 0 < Yn1 N M C D hN hM) (hAneg : A < 0) : | |
| let YY := Yn1 N M C D hN hM | |
| let hCpos : 0 < C := | |
| hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hYpos | |
| mwf N M A B C D hN hM | |
| = | |
| max | |
| 0 | |
| ((A + B) + mwf YY C B A M (M - D - 1) hYpos hCpos) | |
| := by | |
| dsimp only [Yn1, yOf, zfloorDiv, mwf, img, obj, dom, Lean.Elab.WF.paramLet] | |
| let YY : Int := Yn1 N M C D hN hM | |
| have hCpos : 0 < C := hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hYpos | |
| have hDdiv0 : zfloorDiv D M hM = 0 := by | |
| unfold zfloorDiv | |
| exact Int.ediv_eq_zero_of_lt_abs hD0 (by simpa only [abs_of_pos hM] using hDM) | |
| have hZero_le : 0 ≤ mwf N M A B C D hN hM := by | |
| have hx0 : (0 : Int) ∈ dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨le_rfl, sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN)⟩ | |
| have hobj0 := obj_le_mwf N M A B C D 0 hN hM hx0 | |
| have hobj0' : obj A B C D M 0 hM = 0 := by | |
| calc | |
| obj A B C D M 0 hM = A * 0 + B * zfloorDiv D M hM := by simp only [obj, mul_zero, zfloorDiv, | |
| zero_add] | |
| _ = A * 0 + B * 0 := by rw [hDdiv0] | |
| _ = 0 := by ring | |
| rw [hobj0'] at hobj0 | |
| exact hobj0 | |
| have hRec_le : | |
| (A + B) + mwf YY C B A M (M - D - 1) hYpos hCpos ≤ mwf N M A B C D hN hM := by | |
| have hrec_core : mwf YY C B A M (M - D - 1) hYpos hCpos ≤ mwf N M A B C D hN hM - (A + B) := by | |
| unfold mwf | |
| dsimp only [img, obj, zfloorDiv, dom, Lean.Elab.WF.paramLet] | |
| refine Finset.max'_le | |
| (s := img YY C B A M (M - D - 1) hYpos hCpos) | |
| (H := img_nonempty | |
| (N := YY) (M := C) (A := B) (B := A) (C := M) (D := M - D - 1) | |
| hYpos hCpos) | |
| (x := mwf N M A B C D hN hM - (A + B)) ?_ | |
| intro z hz | |
| rcases Finset.mem_image.mp hz with ⟨y, hyDom, rfl⟩ | |
| have hy0 : 0 ≤ y := (Finset.mem_Icc.mp hyDom).1 | |
| have hyLePred : y ≤ YY - 1 := (Finset.mem_Icc.mp hyDom).2 | |
| have hy1_nonneg : 0 ≤ y + 1 := by nlinarith [hy0] | |
| have hy1_leYY : y + 1 ≤ YY := by nlinarith [hyLePred] | |
| have hy1_ne0 : y + 1 ≠ 0 := by nlinarith [hy0] | |
| let x : Int := iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY | |
| have hxDom : x ∈ dom N hN := | |
| iy_left_mem_dom N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY | |
| have hyOf : yOf M C D hM x = y + 1 := | |
| yOf_iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY hy1_ne0 | |
| have hY1 : 1 ≤ Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hxDef0 : x = zfloorDiv (M * (y + 1) + C - D - 1) C hCpos := by | |
| have hneq : y + 1 ≠ 0 := hy1_ne0 | |
| unfold x iy_left | |
| simp only [hneq, ↓reduceDIte, zfloorDiv] | |
| have hxDef : x = zfloorDiv (M * y + M - D - 1) C hCpos + 1 := by | |
| have hCne : C ≠ 0 := ne_of_gt hCpos | |
| calc | |
| x = zfloorDiv (M * (y + 1) + C - D - 1) C hCpos := hxDef0 | |
| _ = zfloorDiv ((M * y + M - D - 1) + C) C hCpos := by ring_nf | |
| _ = zfloorDiv (M * y + M - D - 1) C hCpos + 1 := by | |
| unfold zfloorDiv | |
| simpa only [add_comm, mul_comm, mul_one] using | |
| (Int.add_mul_ediv_right (M * y + M - D - 1) 1 hCne) | |
| have hyDiv : zfloorDiv (C * x + D) M hM = y + 1 := by simpa only [zfloorDiv, yOf] using hyOf | |
| have harg : M * y + (M - D - 1) = M * y + M - D - 1 := by ring | |
| have hObj2 : obj B A M (M - D - 1) C y hCpos = | |
| B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| calc | |
| obj B A M (M - D - 1) C y hCpos | |
| = B * y + A * zfloorDiv (M * y + (M - D - 1)) C hCpos := by simp only [obj, zfloorDiv] | |
| _ = B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos := by rw [harg] | |
| have hObjEq : (A + B) + obj B A M (M - D - 1) C y hCpos = obj A B C D M x hM := by | |
| calc | |
| (A + B) + obj B A M (M - D - 1) C y hCpos | |
| = (A + B) + (B * y + A * zfloorDiv (M * y + M - D - 1) C hCpos) := by rw [hObj2] | |
| _ = B * (y + 1) + A * (zfloorDiv (M * y + M - D - 1) C hCpos + 1) := by ring | |
| _ = B * (y + 1) + A * x := by rw [hxDef] | |
| _ = A * x + B * (y + 1) := by ring | |
| _ = A * x + B * zfloorDiv (C * x + D) M hM := by rw [hyDiv] | |
| _ = obj A B C D M x hM := by simp only [zfloorDiv, obj] | |
| have hObjLe : obj A B C D M x hM ≤ mwf N M A B C D hN hM := | |
| obj_le_mwf_of_mem N M A B C D hN hM hxDom | |
| have hplus : (A + B) + obj B A M (M - D - 1) C y hCpos ≤ mwf N M A B C D hN hM := | |
| hObjEq ▸ hObjLe | |
| nlinarith [hplus] | |
| nlinarith [hrec_core] | |
| have hMax_le : | |
| max 0 ((A + B) + mwf YY C B A M (M - D - 1) hYpos hCpos) | |
| ≤ mwf N M A B C D hN hM := max_le hZero_le hRec_le | |
| have hMwf_le : | |
| mwf N M A B C D hN hM | |
| ≤ max 0 ((A + B) + mwf YY C B A M (M - D - 1) hYpos hCpos) := by | |
| unfold mwf | |
| dsimp only [img, obj, zfloorDiv, dom, Lean.Elab.WF.paramLet] | |
| refine Finset.max'_le | |
| (s := img N M A B C D hN hM) | |
| (H := img_nonempty (N := N) (M := M) (A := A) (B := B) (C := C) (D := D) hN hM) | |
| (x := max 0 ((A + B) + mwf YY C B A M (M - D - 1) hYpos hCpos)) ?_ | |
| intro z hz | |
| rcases Finset.mem_image.mp hz with ⟨x, hxDom, rfl⟩ | |
| let y : Int := yOf M C D hM x | |
| have hy0 : 0 ≤ y := by | |
| have htmp := yOf_nonneg N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxDom) | |
| simpa only [yOf, zfloorDiv, ge_iff_le] using htmp | |
| have hyY : y ≤ YY := by | |
| have htmp := yOf_le_Yn1 N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxDom) | |
| simpa only [yOf, zfloorDiv, Yn1, ge_iff_le] using htmp | |
| by_cases hyZero : y = 0 | |
| · have hx0 : 0 ≤ x := (Finset.mem_Icc.mp hxDom).1 | |
| have hyDiv : zfloorDiv (C * x + D) M hM = 0 := by simpa only [zfloorDiv, yOf] using hyZero | |
| have hObjLe0 : obj A B C D M x hM ≤ 0 := by | |
| have hAx : A * x ≤ 0 := mul_nonpos_of_nonpos_of_nonneg (le_of_lt hAneg) hx0 | |
| calc | |
| obj A B C D M x hM = A * x + B * zfloorDiv (C * x + D) M hM := by simp only [obj, | |
| zfloorDiv] | |
| _ = A * x + B * 0 := by rw [hyDiv] | |
| _ ≤ 0 := by nlinarith [hAx] | |
| exact le_trans hObjLe0 (le_max_left _ _) | |
| · have hyPos : 0 < y := lt_of_le_of_ne hy0 (fun hy' => hyZero hy'.symm) | |
| have hy1 : 0 ≤ y - 1 := by nlinarith [hyPos] | |
| have hy1Le : y - 1 ≤ YY - 1 := by nlinarith [hyY] | |
| have hyDomYY : y - 1 ∈ dom YY hYpos := Finset.mem_Icc.mpr ⟨hy1, hy1Le⟩ | |
| have hRecObj : | |
| obj B A M (M - D - 1) C (y - 1) hCpos ≤ mwf YY C B A M (M - D - 1) hYpos hCpos := | |
| obj_le_mwf_of_mem YY C B A M (M - D - 1) hYpos hCpos hyDomYY | |
| have hDiv : zfloorDiv (C * x + D) M hM = y := by rfl | |
| have hDivEq : (C * x + D) / M = y := by simpa only [zfloorDiv] using hDiv | |
| have hNumLow : y * M ≤ C * x + D := (Int.le_ediv_iff_mul_le hM).1 (le_of_eq hDivEq) | |
| have hLle : zfloorDiv (M * y + C - D - 1) C hCpos ≤ x := by | |
| have hlt : M * y + C - D - 1 < x * C + C := by | |
| have hlt0 : M * y + C - D - 1 < C * x + C := by nlinarith [hNumLow] | |
| simpa only [mul_comm, Order.sub_one_lt_iff, tsub_le_iff_right, ge_iff_le] using hlt0 | |
| exact (Int.ediv_le_iff_le_mul hCpos).2 hlt | |
| have hAub : A * x ≤ A * zfloorDiv (M * y + C - D - 1) C hCpos := by | |
| have htmp : x * A ≤ zfloorDiv (M * y + C - D - 1) C hCpos * A := | |
| mul_le_mul_of_nonpos_right hLle (le_of_lt hAneg) | |
| simpa only [zfloorDiv, ge_iff_le, mul_comm] using htmp | |
| have hCne : C ≠ 0 := ne_of_gt hCpos | |
| have hFloor : | |
| zfloorDiv (M * y + C - D - 1) C hCpos | |
| = zfloorDiv (M * (y - 1) + M - D - 1) C hCpos + 1 := by | |
| calc | |
| zfloorDiv (M * y + C - D - 1) C hCpos | |
| = zfloorDiv ((M * (y - 1) + M - D - 1) + C) C hCpos := by ring_nf | |
| _ = zfloorDiv (M * (y - 1) + M - D - 1) C hCpos + 1 := by | |
| unfold zfloorDiv | |
| simpa only [add_comm, mul_comm, mul_one] using | |
| (Int.add_mul_ediv_right (M * (y - 1) + M - D - 1) 1 hCne) | |
| have hObj2 : obj B A M (M - D - 1) C (y - 1) hCpos = | |
| B * (y - 1) + A * zfloorDiv (M * (y - 1) + M - D - 1) C hCpos := by | |
| have harg : M * (y - 1) + (M - D - 1) = M * (y - 1) + M - D - 1 := by ring | |
| calc | |
| obj B A M (M - D - 1) C (y - 1) hCpos | |
| = B * (y - 1) + A * zfloorDiv (M * (y - 1) + (M - D - 1)) C hCpos := by simp only | |
| [obj, zfloorDiv] | |
| _ = B * (y - 1) + A * zfloorDiv (M * (y - 1) + M - D - 1) C hCpos := by rw [harg] | |
| have hObj_le : | |
| obj A B C D M x hM ≤ (A + B) + obj B A M (M - D - 1) C (y - 1) hCpos := by | |
| calc | |
| obj A B C D M x hM = A * x + B * y := by simp only [obj, zfloorDiv, yOf, y] | |
| _ ≤ A * zfloorDiv (M * y + C - D - 1) C hCpos + B * y := by nlinarith [hAub] | |
| _ = B * y + A * (zfloorDiv (M * (y - 1) + M - D - 1) C hCpos + 1) := by rw [hFloor]; ring | |
| _ = (A + B) + (B * (y - 1) + A * zfloorDiv (M * (y - 1) + M - D - 1) C hCpos) := by ring | |
| _ = (A + B) + obj B A M (M - D - 1) C (y - 1) hCpos := by rw [hObj2] | |
| exact le_trans hObj_le (le_trans (by nlinarith [hRecObj]) (le_max_right _ _)) | |
| exact le_antisymm hMwf_le hMax_le | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `step` 用初期状態表現への書換え。 | |
| 内容: `step_init_equiv` を `St` 形式へ移す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 状態遷移定理列の入口。 | |
| -/ | |
| theorem mwf_step_init_equiv | |
| (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| let U := St.mk (B * zfloorDiv D M hM) 0 N M A B C D hN hM | |
| mwf N M A B C D hN hM | |
| = | |
| max U.r (U.s + mwf U.n U.m U.a U.b U.c U.d U.hn U.hm) := by | |
| dsimp only [zfloorDiv, mwf, img, obj, dom, Lean.Elab.WF.paramLet] | |
| simpa only [zero_add, right_eq_sup, mwf, img, obj, zfloorDiv, dom] using | |
| step_init_equiv N M A B C D hN hM | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `step_normalize` は評価式を保存。 | |
| 内容: `normalize_max` とフィールド展開を結合。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `step` 正しさの前半。 | |
| -/ | |
| theorem mwf_step_normalize_equiv | |
| (U : St) : | |
| let V := step_normalize U | |
| max U.r (U.s + st_mwf U) | |
| = | |
| max V.r (V.s + stnorm_mwf V) := by | |
| dsimp only [step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, normD, st_mwf, mwf, img, | |
| obj, dom, stnorm_mwf, Lean.Elab.WF.paramLet] | |
| simpa only [mwf, img, obj, zfloorDiv, dom, normS, normA, normC, zfloorMod, normD] using | |
| normalize_max U.r U.s U.n U.m U.a U.b U.c U.d U.hn U.hm | |
| /-- | |
| 入力/前提: U : StNorm、hY0 : stnorm_y U = 0。 | |
| 主張: `Y=0` 分岐で評価式は不変。 | |
| 内容: `mwf_yn1_zero` と `step_reduce_y0` 展開で一致化。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: reduce 同値の停止枝。 | |
| -/ | |
| theorem mwf_step_reduce_equiv_y0 | |
| (U : StNorm) | |
| (hY0 : stnorm_y U = 0) : | |
| let V := step_reduce_y0 U hY0 | |
| max U.r (U.s + stnorm_mwf U) | |
| = | |
| max V.r (V.s + st_mwf V) := by | |
| have hcore := | |
| mwf_yn1_zero U.n U.m U.a U.b U.c U.d U.hn U.hm U.hC0 U.hD0 U.hCM U.hDM hY0 | |
| have hlift0 : | |
| max U.r (U.s + stnorm_mwf U) = | |
| max U.r (U.s + max 0 (U.a * (U.n - 1))) := by | |
| simpa only [stnorm_mwf, mwf, img, obj, zfloorDiv, dom] using | |
| congrArg (fun t => max U.r (U.s + t)) hcore | |
| have hlift : | |
| max U.r (U.s + stnorm_mwf U) = | |
| max (max U.r U.s) (U.s + U.a * (U.n - 1)) := by | |
| calc | |
| max U.r (U.s + stnorm_mwf U) = max U.r (U.s + max 0 (U.a * (U.n - 1))) := hlift0 | |
| _ = max U.r (max U.s (U.s + U.a * (U.n - 1))) := by simp only [add_max, add_zero] | |
| _ = max (max U.r U.s) (U.s + U.a * (U.n - 1)) := by simp only [max_assoc] | |
| have hbase : mwf 1 1 0 0 0 0 (by decide) (by decide) = 0 := by | |
| unfold mwf img dom obj zfloorDiv | |
| simp only [zero_mul, add_zero, sub_self, Finset.Icc_self, Finset.image_singleton, | |
| Finset.max'_singleton] | |
| have hstep : | |
| max (step_reduce_y0 U hY0).r ((step_reduce_y0 U hY0).s + st_mwf (step_reduce_y0 U hY0)) = | |
| max (max U.r U.s) (U.s + U.a * (U.n - 1)) := by | |
| simp only [step_reduce_y0, Int.max_assoc, st_mwf, mwf, img, obj, zero_mul, zfloorDiv, add_zero, | |
| dom, sub_self, Finset.Icc_self, Finset.image_singleton, Finset.max'_singleton, max_self] | |
| exact hlift.trans hstep.symm | |
| /-- | |
| 入力/前提: U : StNorm、hYpos : 0 < stnorm_y U、hAnonneg : 0 ≤ U.a。 | |
| 主張: `Y>0 ∧ A≥0` 分岐で評価式は不変。 | |
| 内容: `mwf_yn1_pos_a_nonneg` と状態展開で照合。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: reduce 同値の正傾き枝。 | |
| -/ | |
| theorem mwf_step_reduce_equiv_ypos_a_nonneg | |
| (U : StNorm) | |
| (hYpos : 0 < stnorm_y U) | |
| (hAnonneg : 0 ≤ U.a) : | |
| let V := step_reduce_ypos_a_nonneg U hYpos hAnonneg | |
| max U.r (U.s + stnorm_mwf U) | |
| = | |
| max V.r (V.s + st_mwf V) := by | |
| dsimp only [step_reduce_ypos_a_nonneg, stnorm_y, Yn1, yOf, zfloorDiv, stnorm_mwf, mwf, img, obj, | |
| dom, st_mwf, Lean.Elab.WF.paramLet] | |
| have hcore := | |
| mwf_yn1_pos_a_nonneg U.n U.m U.a U.b U.c U.d | |
| U.hn U.hm U.hC0 U.hD0 U.hCM U.hDM | |
| (by simpa only [Yn1, yOf, zfloorDiv, stnorm_y] using hYpos) hAnonneg | |
| have hcore' : | |
| max U.r (U.s + stnorm_mwf U) | |
| = | |
| max U.r | |
| (U.s + | |
| max | |
| (U.a * (U.n - 1) + U.b * stnorm_y U) | |
| (mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYpos))) := by | |
| simpa only [stnorm_mwf, mwf, img, obj, zfloorDiv, dom, stnorm_y, Yn1, yOf] using | |
| congrArg (fun t => max U.r (U.s + t)) hcore | |
| calc | |
| max U.r (U.s + stnorm_mwf U) | |
| = max U.r | |
| (U.s + | |
| max | |
| (U.a * (U.n - 1) + U.b * stnorm_y U) | |
| (mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYpos))) := hcore' | |
| _ = | |
| max | |
| (max U.r (U.s + (U.a * (U.n - 1) + U.b * stnorm_y U))) | |
| (U.s + | |
| mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYpos)) := by | |
| rw [add_max] | |
| rw [max_assoc] | |
| _ = | |
| max (step_reduce_ypos_a_nonneg U hYpos hAnonneg).r | |
| ((step_reduce_ypos_a_nonneg U hYpos hAnonneg).s + | |
| st_mwf (step_reduce_ypos_a_nonneg U hYpos hAnonneg)) := by | |
| rfl | |
| /-- | |
| 入力/前提: U : StNorm、hYpos : 0 < stnorm_y U、hAneg : U.a < 0。 | |
| 主張: `Y>0 ∧ A<0` 分岐で評価式は不変。 | |
| 内容: `mwf_yn1_pos_a_neg` と状態展開で照合。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: reduce 同値の負傾き枝。 | |
| -/ | |
| theorem mwf_step_reduce_equiv_ypos_a_neg | |
| (U : StNorm) | |
| (hYpos : 0 < stnorm_y U) | |
| (hAneg : U.a < 0) : | |
| let V := step_reduce_ypos_a_neg U hYpos hAneg | |
| max U.r (U.s + stnorm_mwf U) | |
| = | |
| max V.r (V.s + st_mwf V) := by | |
| dsimp only [step_reduce_ypos_a_neg, stnorm_y, Yn1, yOf, zfloorDiv, stnorm_mwf, mwf, img, obj, dom, | |
| st_mwf, Lean.Elab.WF.paramLet] | |
| have hcore := | |
| mwf_yn1_pos_a_neg U.n U.m U.a U.b U.c U.d | |
| U.hn U.hm U.hC0 U.hD0 U.hCM U.hDM | |
| (by simpa only [Yn1, yOf, zfloorDiv, stnorm_y] using hYpos) hAneg | |
| have hcore' : | |
| max U.r (U.s + stnorm_mwf U) | |
| = | |
| max U.r | |
| (U.s + | |
| max | |
| 0 | |
| ((U.a + U.b) + | |
| mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYpos))) := by | |
| simpa only [stnorm_mwf, mwf, img, obj, zfloorDiv, dom, stnorm_y, Yn1, yOf] using | |
| congrArg (fun t => max U.r (U.s + t)) hcore | |
| calc | |
| max U.r (U.s + stnorm_mwf U) | |
| = max U.r | |
| (U.s + | |
| max | |
| 0 | |
| ((U.a + U.b) + | |
| mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one | |
| U.n U.m U.c U.d | |
| U.hn U.hm U.hC0 U.hD0 U.hDM | |
| hYpos))) := hcore' | |
| _ = max (max U.r U.s) | |
| (U.s + | |
| ((U.a + U.b) + | |
| mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYpos))) := by | |
| rw [add_max] | |
| simp only [add_zero, mwf, img, obj, zfloorDiv, dom, stnorm_y, Yn1, yOf, Int.max_assoc] | |
| _ = max (max U.r U.s) | |
| ((U.s + (U.a + U.b)) + | |
| mwf (stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos | |
| (hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM hYpos)) := by | |
| simp only [mwf, img, obj, zfloorDiv, dom, stnorm_y, Yn1, yOf, add_assoc, Int.max_assoc] | |
| _ = | |
| max (step_reduce_ypos_a_neg U hYpos hAneg).r | |
| ((step_reduce_ypos_a_neg U hYpos hAneg).s + | |
| st_mwf (step_reduce_ypos_a_neg U hYpos hAneg)) := by | |
| rfl | |
| /-- | |
| 入力/前提: U : StNorm。 | |
| 主張: `step_reduce` 全体で評価式は不変。 | |
| 内容: `Y` と `A` の符号で分岐し枝定理を貼る。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: reduce 正しさの統合定理。 | |
| -/ | |
| theorem mwf_step_reduce_equiv | |
| (U : StNorm) : | |
| let V := step_reduce U | |
| max U.r (U.s + stnorm_mwf U) | |
| = | |
| max V.r (V.s + st_mwf V) := by | |
| by_cases hY0 : stnorm_y U = 0 | |
| · have hY0' : (U.c * (U.n - 1) + U.d) / U.m = 0 := by | |
| simpa only [stnorm_y, Yn1, yOf, zfloorDiv] using hY0 | |
| simpa only [stnorm_mwf, mwf, img, obj, zfloorDiv, dom, step_reduce, stnorm_y, Yn1, yOf, hY0', | |
| ↓reduceDIte, step_reduce_y0, Int.max_assoc, st_mwf, zero_mul, add_zero, | |
| EuclideanDomain.div_one, mul_zero, sub_self, Finset.Icc_self, Finset.image_singleton, | |
| Finset.max'_singleton, max_self] using mwf_step_reduce_equiv_y0 U hY0 | |
| · have hYnonneg : 0 ≤ stnorm_y U := | |
| Y_nonneg U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 | |
| have hYpos : 0 < stnorm_y U := lt_of_le_of_ne hYnonneg (fun h => hY0 h.symm) | |
| have hYpos' : 0 < (U.c * (U.n - 1) + U.d) / U.m := by | |
| simpa only [stnorm_y, Yn1, yOf, zfloorDiv] using hYpos | |
| have hne' : (U.c * (U.n - 1) + U.d) / U.m ≠ 0 := ne_of_gt hYpos' | |
| by_cases hAnonneg : 0 ≤ U.a | |
| · simpa only [stnorm_mwf, mwf, img, obj, zfloorDiv, dom, step_reduce, stnorm_y, Yn1, yOf, hne', | |
| ↓reduceDIte, hAnonneg, step_reduce_ypos_a_nonneg, st_mwf, Int.max_assoc, | |
| Int.max_add_left] using mwf_step_reduce_equiv_ypos_a_nonneg U hYpos hAnonneg | |
| · have hAneg : U.a < 0 := lt_of_not_ge hAnonneg | |
| have hnot : ¬ (0 ≤ U.a) := hAnonneg | |
| simpa only [stnorm_mwf, mwf, img, obj, zfloorDiv, dom, step_reduce, stnorm_y, Yn1, yOf, hne', | |
| ↓reduceDIte, hnot, step_reduce_ypos_a_neg, st_mwf, Int.max_assoc] using | |
| mwf_step_reduce_equiv_ypos_a_neg U hYpos hAneg | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `step` 1回で評価式は不変。 | |
| 内容: normalize 同値と reduce 同値を合成。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 反復アルゴリズム正しさの中核。 | |
| -/ | |
| theorem mwf_step_equiv | |
| (U : St) : | |
| let V := step U | |
| max U.r (U.s + mwf U.n U.m U.a U.b U.c U.d U.hn U.hm) | |
| = | |
| max V.r (V.s + mwf V.n V.m V.a V.b V.c V.d V.hn V.hm) := by | |
| dsimp only [step, step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, normD, step_reduce, | |
| stnorm_y, Yn1, yOf, step_reduce_y0, step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, | |
| dite_eq_ite, Lean.Elab.WF.paramLet, mwf, img, obj, dom] | |
| calc | |
| max U.r (U.s + mwf U.n U.m U.a U.b U.c U.d U.hn U.hm) | |
| = max (step_normalize U).r ((step_normalize U).s + stnorm_mwf (step_normalize U)) := by | |
| simpa only [mwf, img, obj, zfloorDiv, dom, step_normalize, normS, normA, normC, zfloorMod, | |
| normD, stnorm_mwf, st_mwf] using (mwf_step_normalize_equiv U) | |
| _ = max (step_reduce (step_normalize U)).r | |
| ((step_reduce (step_normalize U)).s + st_mwf (step_reduce (step_normalize U))) := by | |
| simpa only [step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, normD, stnorm_mwf, | |
| mwf, img, obj, dom, step_reduce, stnorm_y, Yn1, yOf, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, st_mwf] using | |
| (mwf_step_reduce_equiv (step_normalize U)) | |
| _ = max (step_reduce (step_normalize U)).r | |
| ((step_reduce (step_normalize U)).s + | |
| mwf (step_reduce (step_normalize U)).n (step_reduce (step_normalize U)).m | |
| (step_reduce (step_normalize U)).a (step_reduce (step_normalize U)).b | |
| (step_reduce (step_normalize U)).c (step_reduce (step_normalize U)).d | |
| (step_reduce (step_normalize U)).hn (step_reduce (step_normalize U)).hm) := by | |
| rfl | |
| /-- | |
| 入力/前提: U : St、hc0 : U.c = 0。 | |
| 主張: `U.c=0` なら正規化後も `stnorm_y=0`。 | |
| 内容: `normC 0 = 0` と `Y_eq_zero_of_C_eq_zero` を適用。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 停止分岐への接続。 | |
| -/ | |
| lemma stnorm_y_step_normalize_eq_zero | |
| (U : St) (hc0 : U.c = 0) : | |
| stnorm_y (step_normalize U) = 0 := by | |
| have hCmod0 : U.c % U.m = 0 := by | |
| simpa only [hc0] using (Int.zero_emod U.m) | |
| simpa only [stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, normC, zfloorMod, hCmod0, | |
| normD, zero_mul, zero_add] using | |
| (Y_eq_zero_of_C_eq_zero U.n U.m (U.c % U.m) (U.d % U.m) U.hn U.hm | |
| (Int.emod_nonneg _ (ne_of_gt U.hm)) (Int.emod_lt_of_pos _ U.hm) hCmod0) | |
| /-- | |
| 入力/前提: 追加の仮定なし。 | |
| 主張: 基底状態 `mwf 1 1 0 0 0 0 = 0`。 | |
| 内容: `Yn1=0` ケース公式を直接適用。 | |
| 証明: 式変形で示す。 | |
| 役割: 停止枝の最終値評価。 | |
| -/ | |
| lemma mwf_one_one_zero : | |
| mwf 1 1 0 0 0 0 (by decide) (by decide) = 0 := by | |
| have hY0 : Yn1 1 1 0 0 (by decide) (by decide) = 0 := by | |
| exact Y_eq_zero_of_C_eq_zero 1 1 0 0 (by decide) (by decide) (by decide) (by decide) rfl | |
| have h := mwf_yn1_zero 1 1 0 0 0 0 (by decide) (by decide) | |
| (by decide) (by decide) (by decide) (by decide) hY0 | |
| calc | |
| mwf 1 1 0 0 0 0 (by decide) (by decide) = max 0 (0 * (1 - 1)) := h | |
| _ = 0 := by simp only [sub_self, mul_zero, max_self] | |
| /-- | |
| 入力/前提: W : StNorm、h : stnorm_y W = 0。 | |
| 主張: `step_reduce_y0` 後の `st_mwf` は 0。 | |
| 内容: 遷移先が基底状態であることを使う。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 終了時の `max` 簡約に使用。 | |
| -/ | |
| lemma st_mwf_step_reduce_y0_zero | |
| (W : StNorm) (h : stnorm_y W = 0) : | |
| st_mwf (step_reduce_y0 W h) = 0 := by | |
| dsimp only [step_reduce_y0, st_mwf, mwf, img, obj, zfloorDiv, dom, Int.reduceSub] | |
| exact mwf_one_one_zero | |
| /-- | |
| 入力/前提: W : StNorm、h : stnorm_y W = 0。 | |
| 主張: 仮定 `stnorm_y=0` で `step_reduce` は `y0` 枝に一致。 | |
| 内容: 外側 `if` を仮定で簡約。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 停止証明で分岐を確定。 | |
| -/ | |
| lemma step_reduce_eq_y0 | |
| (W : StNorm) (h : stnorm_y W = 0) : | |
| step_reduce W = step_reduce_y0 W h := by | |
| have h' : (W.c * (W.n - 1) + W.d) / W.m = 0 := by | |
| simpa only [stnorm_y, Yn1, yOf, zfloorDiv] using h | |
| unfold step_reduce | |
| simp only [stnorm_y, Yn1, yOf, zfloorDiv, h', ↓reduceDIte, step_reduce_y0, Int.max_assoc] | |
| /-- | |
| 入力/前提: W : StNorm、hPos : 0 < stnorm_y W、hAnonneg : 0 ≤ W.a。 | |
| 主張: `stnorm_y>0 ∧ a≥0` で `step_reduce` は正傾き枝に一致。 | |
| 内容: 2段の `if` を仮定で簡約。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 縮小証明で分岐を確定。 | |
| -/ | |
| lemma step_reduce_eq_ypos_a_nonneg | |
| (W : StNorm) (hPos : 0 < stnorm_y W) (hAnonneg : 0 ≤ W.a) : | |
| step_reduce W = step_reduce_ypos_a_nonneg W hPos hAnonneg := by | |
| have hPos' : 0 < (W.c * (W.n - 1) + W.d) / W.m := by | |
| simpa only [stnorm_y, Yn1, yOf, zfloorDiv] using hPos | |
| have hne' : (W.c * (W.n - 1) + W.d) / W.m ≠ 0 := ne_of_gt hPos' | |
| unfold step_reduce | |
| simp only [stnorm_y, Yn1, yOf, zfloorDiv, hne', ↓reduceDIte, hAnonneg, step_reduce_ypos_a_nonneg] | |
| /-- | |
| 入力/前提: W : StNorm、hPos : 0 < stnorm_y W、hAneg : W.a < 0。 | |
| 主張: `stnorm_y>0 ∧ a<0` で `step_reduce` は負傾き枝に一致。 | |
| 内容: 2段の `if` を仮定で簡約。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 縮小証明で分岐を確定。 | |
| -/ | |
| lemma step_reduce_eq_ypos_a_neg | |
| (W : StNorm) (hPos : 0 < stnorm_y W) (hAneg : W.a < 0) : | |
| step_reduce W = step_reduce_ypos_a_neg W hPos hAneg := by | |
| have hPos' : 0 < (W.c * (W.n - 1) + W.d) / W.m := by | |
| simpa only [stnorm_y, Yn1, yOf, zfloorDiv] using hPos | |
| have hne' : (W.c * (W.n - 1) + W.d) / W.m ≠ 0 := ne_of_gt hPos' | |
| unfold step_reduce | |
| have hnot : ¬ (0 ≤ W.a) := not_le.mpr hAneg | |
| simp only [stnorm_y, Yn1, yOf, zfloorDiv, hne', ↓reduceDIte, hnot, step_reduce_ypos_a_neg] | |
| /-- | |
| 入力/前提: `U : St`、`hc0 : (step U).c = 0`。 | |
| 主張: `(step U).c = 0` なら `stnorm_y (step_normalize U) = 0`。 | |
| 内容: `stnorm_y` が正なら `step` の `c` は `m` に更新され矛盾することを示す。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: 停止条件を正規化側へ戻す補助。 | |
| -/ | |
| lemma stnorm_y_step_normalize_eq_zero_of_step_c_zero | |
| (U : St) (hc0 : (step U).c = 0) : | |
| stnorm_y (step_normalize U) = 0 := by | |
| by_cases hY0 : stnorm_y (step_normalize U) = 0 | |
| · exact hY0 | |
| · have hYnonneg : 0 ≤ stnorm_y (step_normalize U) := | |
| Y_nonneg (step_normalize U).n (step_normalize U).m | |
| (step_normalize U).c (step_normalize U).d | |
| (step_normalize U).hn (step_normalize U).hm | |
| (step_normalize U).hC0 (step_normalize U).hD0 | |
| have hYpos : 0 < stnorm_y (step_normalize U) := | |
| lt_of_le_of_ne hYnonneg (by simpa only [stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, | |
| normA, normC, zfloorMod, normD, ne_eq, eq_comm] using hY0) | |
| by_cases hAnonneg : 0 ≤ (step_normalize U).a | |
| · have hstep : | |
| step U = | |
| step_reduce_ypos_a_nonneg (step_normalize U) hYpos hAnonneg := by | |
| unfold step | |
| exact step_reduce_eq_ypos_a_nonneg (step_normalize U) hYpos hAnonneg | |
| have hc : (step U).c = (step_normalize U).m := congrArg St.c hstep | |
| have hm0 : U.m ≠ 0 := ne_of_gt U.hm | |
| have hc' : (step U).c = U.m := by simpa only [step, step_reduce, stnorm_y, Yn1, yOf, | |
| zfloorDiv, step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, | |
| Int.max_assoc, step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] using hc | |
| exact (hm0 (hc'.symm.trans hc0)).elim | |
| · have hAneg : (step_normalize U).a < 0 := lt_of_not_ge hAnonneg | |
| have hstep : | |
| step U = | |
| step_reduce_ypos_a_neg (step_normalize U) hYpos hAneg := by | |
| unfold step | |
| exact step_reduce_eq_ypos_a_neg (step_normalize U) hYpos hAneg | |
| have hc : (step U).c = (step_normalize U).m := congrArg St.c hstep | |
| have hm0 : U.m ≠ 0 := ne_of_gt U.hm | |
| have hc' : (step U).c = U.m := by simpa only [step, step_reduce, stnorm_y, Yn1, yOf, | |
| zfloorDiv, step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, | |
| Int.max_assoc, step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] using hc | |
| exact (hm0 (hc'.symm.trans hc0)).elim | |
| /-! 停止条件において答えを得る方法 -/ | |
| /-- | |
| 入力/前提: U : St、hc0 : U.c = 0。 | |
| 主張: 停止条件 `c=0` では答えは `(step U).r`。 | |
| 内容: `y0` 分岐確定と `st_mwf=0` で `max` を潰す。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 実際の値読み出し定理。 | |
| -/ | |
| theorem mwf_step_reduce_result | |
| (U : St) (hc0 : U.c = 0) : | |
| max U.r (U.s + st_mwf U) = (step U).r := by | |
| have hstepEq : | |
| max U.r (U.s + st_mwf U) | |
| = | |
| max (step U).r ((step U).s + st_mwf (step U)) := by | |
| simpa only [st_mwf, mwf, img, obj, zfloorDiv, dom, step, step_reduce, stnorm_y, Yn1, yOf, | |
| step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] using (mwf_step_equiv U) | |
| have hY0 : stnorm_y (step_normalize U) = 0 := stnorm_y_step_normalize_eq_zero U hc0 | |
| have hstepY0 : | |
| step_reduce (step_normalize U) = step_reduce_y0 (step_normalize U) hY0 := | |
| step_reduce_eq_y0 (step_normalize U) hY0 | |
| have hmwf0 : st_mwf (step_reduce_y0 (step_normalize U) hY0) = 0 := | |
| st_mwf_step_reduce_y0_zero (step_normalize U) hY0 | |
| have htail : | |
| max (step U).r ((step U).s + st_mwf (step U)) = (step U).r := by | |
| change | |
| max (step_reduce (step_normalize U)).r | |
| ((step_reduce (step_normalize U)).s + st_mwf (step_reduce (step_normalize U))) | |
| = | |
| (step_reduce (step_normalize U)).r | |
| rw [hstepY0] | |
| have hs : | |
| (step_reduce_y0 (step_normalize U) hY0).s = | |
| (step_reduce_y0 (step_normalize U) hY0).r := by | |
| simp only [step_reduce_y0, step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, normD, | |
| Int.max_assoc] | |
| rw [hs, hmwf0] | |
| simp only [step_reduce_y0, step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, normD, | |
| Int.max_assoc, add_zero, max_self] | |
| exact hstepEq.trans htail | |
| /-- | |
| 入力/前提: U : St、hc0 : U.c = 0。 | |
| 主張: `U.c = 0` なら 1 ステップ後も `(step U).c = 0`。 | |
| 内容: `stnorm_y=0` の枝へ簡約し `step_reduce_y0` の定義から従う。 | |
| 証明: 式変形で示す。 | |
| 役割: 停止条件の不変性。 | |
| -/ | |
| lemma step_c_zero_of_c_zero (U : St) (hc0 : U.c = 0) : (step U).c = 0 := by | |
| have hY0 : stnorm_y (step_normalize U) = 0 := | |
| stnorm_y_step_normalize_eq_zero U hc0 | |
| have hstep : | |
| step_reduce (step_normalize U) = | |
| step_reduce_y0 (step_normalize U) hY0 := | |
| step_reduce_eq_y0 (step_normalize U) hY0 | |
| change (step_reduce (step_normalize U)).c = 0 | |
| rw [hstep] | |
| simp only [step_reduce_y0, step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, normD, | |
| Int.max_assoc] | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `(step U).c = 0` か `(step U).m = U.c % U.m` が成り立つ。 | |
| 内容: `step_reduce` の分岐を展開して `m` 更新形を読み取る。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: Euclid 形更新か停止かの判定に使う。 | |
| -/ | |
| lemma step_m_or (U : St) : (step U).c = 0 ∨ (step U).m = U.c % U.m := by | |
| let W := step_normalize U | |
| by_cases hy0 : stnorm_y W = 0 | |
| · left | |
| have hstep : step U = step_reduce_y0 W hy0 := by | |
| unfold step | |
| exact step_reduce_eq_y0 W hy0 | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using (congrArg St.c hstep) | |
| · have hpos : 0 < stnorm_y W := by | |
| have hge : | |
| 0 ≤ stnorm_y W := | |
| Y_nonneg W.n W.m W.c W.d W.hn W.hm W.hC0 W.hD0 | |
| exact lt_of_le_of_ne hge (by symm; exact hy0) | |
| by_cases hAnonneg : 0 ≤ W.a | |
| · right | |
| have hstep : step U = step_reduce_ypos_a_nonneg W hpos hAnonneg := by | |
| unfold step | |
| exact step_reduce_eq_ypos_a_nonneg W hpos hAnonneg | |
| have hm : (step U).m = W.c := congrArg St.m hstep | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using hm | |
| · right | |
| have hstep : step U = step_reduce_ypos_a_neg W hpos (lt_of_not_ge hAnonneg) := by | |
| unfold step | |
| exact step_reduce_eq_ypos_a_neg W hpos (lt_of_not_ge hAnonneg) | |
| have hm : (step U).m = W.c := congrArg St.m hstep | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using hm | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `(step U).c = 0` または `(step U).c = U.m`。 | |
| 内容: `step_reduce` の分岐を展開して `c` 更新形を読み取る。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: Euclid 形更新の片方成分を特定する。 | |
| -/ | |
| lemma step_c_or (U : St) : (step U).c = 0 ∨ (step U).c = U.m := by | |
| let W := step_normalize U | |
| by_cases hy0 : stnorm_y W = 0 | |
| · left | |
| have hstep : step U = step_reduce_y0 W hy0 := by | |
| unfold step | |
| exact step_reduce_eq_y0 W hy0 | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using (congrArg St.c hstep) | |
| · have hpos : 0 < stnorm_y W := by | |
| have hge : | |
| 0 ≤ stnorm_y W := | |
| Y_nonneg W.n W.m W.c W.d W.hn W.hm W.hC0 W.hD0 | |
| exact lt_of_le_of_ne hge (by symm; exact hy0) | |
| by_cases hAnonneg : 0 ≤ W.a | |
| · right | |
| have hstep : step U = step_reduce_ypos_a_nonneg W hpos hAnonneg := by | |
| unfold step | |
| exact step_reduce_eq_ypos_a_nonneg W hpos hAnonneg | |
| have hc : (step U).c = W.m := congrArg St.c hstep | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using hc | |
| · right | |
| have hstep : step U = step_reduce_ypos_a_neg W hpos (lt_of_not_ge hAnonneg) := by | |
| unfold step | |
| exact step_reduce_eq_ypos_a_neg W hpos (lt_of_not_ge hAnonneg) | |
| have hc : (step U).c = W.m := congrArg St.c hstep | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using hc | |
| /-! ステップで状態が縮小することの証明 -/ | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: 1ステップで `m` が減るか `c=0` になる。 | |
| 内容: `step_reduce` の3分岐を場合分け。 | |
| 証明: 場合分け・式変形で示す。 | |
| 役割: 反復の進捗・停止保証。 | |
| -/ | |
| theorem mwf_step_reduce_reduction | |
| (U : St) : U.m > (step U).m ∨ (step U).c = 0 := by | |
| cases step_m_or U with | |
| | inl hc0 => exact Or.inr hc0 | |
| | inr hm => | |
| left | |
| have hlt : (step U).m < U.m := by | |
| calc | |
| (step U).m = U.c % U.m := hm | |
| _ < U.m := Int.emod_lt_of_pos U.c U.hm | |
| exact hlt | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: 1 ステップは「停止」か「Euclid 形の更新」になる。 | |
| 内容: `step_c_or` と `step_m_or` を組み合わせて結論を得る。 | |
| 証明: 場合分け・式変形で示す。 | |
| 役割: Euclid 反復との対応付けに使う。 | |
| -/ | |
| lemma step_euclid_or_stop (U : St) : | |
| (step U).c = 0 ∨ ((step U).c = U.m ∧ (step U).m = U.c % U.m) := by | |
| cases step_c_or U with | |
| | inl hc0 => exact Or.inl hc0 | |
| | inr hc1 => | |
| cases step_m_or U with | |
| | inl hm0 => | |
| have hm0' : U.m = 0 := by | |
| calc | |
| U.m = (step U).c := by | |
| symm | |
| exact hc1 | |
| _ = 0 := hm0 | |
| exact False.elim ((ne_of_gt U.hm) hm0') | |
| | inr hm1 => | |
| exact Or.inr ⟨hc1, hm1⟩ | |
| /-- | |
| 入力/前提: `U : St`、`h : (step (step U)).c ≠ 0`。 | |
| 主張: 前処理 1 ステップ後、次のステップが停止しなければ Euclid 1 ステップに一致。 | |
| 内容: `step_euclid_or_stop` を `step U` に適用し停止分岐を排除する。 | |
| 証明: 場合分けで示す。 | |
| 役割: Euclid 反復解析のための橋渡し。 | |
| -/ | |
| lemma step_after_preprocess_euclid (U : St) (h : (step (step U)).c ≠ 0) : | |
| (step (step U)).c = (step U).m ∧ (step (step U)).m = (step U).c % (step U).m := by | |
| cases step_euclid_or_stop (step U) with | |
| | inl hc0 => exact False.elim (h hc0) | |
| | inr hpair => exact hpair | |
| /-! | |
| `Nat.greatestFib` と `Int.fib` の橋渡し補題。 | |
| -/ | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `Int.fib (Nat.greatestFib n) ≤ n`。 | |
| 内容: `Nat.fib_greatestFib_le` を `Int` にキャストする。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `greatestFib` の上界評価に使う。 | |
| -/ | |
| theorem fib_greatestFib_le_int (n : Nat) : (Int.fib (Nat.greatestFib n) : Int) ≤ n := by | |
| simpa only [Int.fib_natCast, Nat.cast_le] using (by exact_mod_cast (Nat.fib_greatestFib_le n)) | |
| /-- | |
| 入力/前提: m n : Nat、Int.fib m : Int。 | |
| 主張: `m ≤ Nat.greatestFib n ↔ (Int.fib m : Int) ≤ n`。 | |
| 内容: `Nat.le_greatestFib` を `Int` に持ち上げた同値。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `greatestFib` と `Int.fib` の比較に使う。 | |
| -/ | |
| @[simp] | |
| theorem le_greatestFib_int {m n : Nat} : | |
| m ≤ Nat.greatestFib n ↔ (Int.fib m : Int) ≤ n := by | |
| constructor | |
| · intro h | |
| have h' : Nat.fib m ≤ n := (Nat.le_greatestFib (m := m) (n := n)).1 h | |
| simpa only [Int.fib_natCast, Nat.cast_le, ge_iff_le] using (by exact_mod_cast h') | |
| · intro h | |
| have h' : (Nat.fib m : Int) ≤ n := by | |
| simpa only [Nat.cast_le, Int.fib_natCast] using h | |
| have h'' : Nat.fib m ≤ n := by | |
| exact_mod_cast h' | |
| exact (Nat.le_greatestFib (m := m) (n := n)).2 h'' | |
| /-- | |
| 入力/前提: m n : Nat、m : Int。 | |
| 主張: `Nat.greatestFib m < n ↔ (m : Int) < Int.fib n`。 | |
| 内容: `Nat.greatestFib_lt` を `Int` にキャストして同値化する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `greatestFib` の下界比較に使う。 | |
| -/ | |
| @[simp] | |
| theorem greatestFib_lt_int {m n : Nat} : | |
| Nat.greatestFib m < n ↔ (m : Int) < Int.fib n := by | |
| constructor | |
| · intro h | |
| have h' : m < Nat.fib n := (Nat.greatestFib_lt (m := m) (n := n)).1 h | |
| simpa only [Int.fib_natCast, Nat.cast_lt, gt_iff_lt] using (by exact_mod_cast h') | |
| · intro h | |
| have h' : (m : Int) < Nat.fib n := by | |
| simpa only [Nat.cast_lt, Int.fib_natCast] using h | |
| have h'' : m < Nat.fib n := by | |
| exact_mod_cast h' | |
| exact (Nat.greatestFib_lt (m := m) (n := n)).2 h'' | |
| /-- | |
| 入力/前提: n : Nat、n : Int。 | |
| 主張: `(n : Int) < Int.fib (Nat.greatestFib n + 1)`。 | |
| 内容: `Nat.lt_fib_greatestFib_add_one` を `Int` にキャストする。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `stepBoundOfM` の停止上界に使う。 | |
| -/ | |
| theorem lt_fib_greatestFib_add_one_int (n : Nat) : | |
| (n : Int) < Int.fib (Nat.greatestFib n + 1) := by | |
| set k := Nat.greatestFib n + 1 | |
| have h_nat : n < Nat.fib k := by | |
| dsimp only [k] | |
| exact Nat.lt_fib_greatestFib_add_one n | |
| have h1 : (n : Int) < (Nat.fib k : Int) := by | |
| exact_mod_cast h_nat | |
| have h2 : (Nat.fib k : Int) = Int.fib k := by | |
| simp only [Int.fib_natCast] | |
| exact lt_of_lt_of_eq h1 h2 | |
| /-- | |
| 目的: `step` を `k` 回適用した状態 `stepN k U` を定義する。 | |
| 定義: `k=0` で恒等、`k+1` で `step` を 1 回進めて再帰。 | |
| 入力/前提: `k : Nat`、`U : St`。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 反復回数の解析基盤。 | |
| -/ | |
| def stepN : Nat → St → St | |
| | 0, U => U | |
| | k + 1, U => stepN k (step U) | |
| /-- | |
| 入力/前提: t : Nat、V : St、h : V.c = 0。 | |
| 主張: `V.c = 0` なら任意回数の `stepN` でも `c=0`。 | |
| 内容: `t` による帰納法で `step_c_zero_of_c_zero` を用いる。 | |
| 証明: 帰納法・既存補題の書き換えで示す。 | |
| 役割: 停止条件の不変性。 | |
| -/ | |
| lemma stepN_c_zero_of_c_zero (t : Nat) (V : St) (h : V.c = 0) : | |
| (stepN t V).c = 0 := by | |
| induction t generalizing V with | |
| | zero => | |
| simpa only [stepN] using h | |
| | succ t ih => | |
| have hstep : (step V).c = 0 := step_c_zero_of_c_zero V h | |
| simpa only [stepN, step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, | |
| normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] using (ih (step V) hstep) | |
| /-- | |
| 目的: Nat 版 Euclid 1 ステップ `euclid_step` を定義する。 | |
| 定義: `m=0` なら `(c,0)` に据え置き、そうでなければ `(m, c % m)`。 | |
| 入力/前提: c m : Nat。 | |
| 出力: 型 `Nat × Nat` の値を返す。 | |
| 役割: Euclid 反復の基本操作。 | |
| -/ | |
| def euclid_step (c m : Nat) : Nat × Nat := | |
| if _ : m = 0 then (c, 0) else (m, c % m) | |
| /-- | |
| 目的: Euclid を `k` 回適用した結果 `euclidN` を定義する。 | |
| 定義: `euclid_step` を `k` 回合成する再帰。 | |
| 入力/前提: `k c m : Nat`。 | |
| 出力: 型 `Nat × Nat` の値を返す。 | |
| 役割: `stepN` と対応付ける対象。 | |
| -/ | |
| def euclidN : Nat → Nat → Nat → Nat × Nat | |
| | 0, c, m => (c, m) | |
| | k + 1, c, m => let p := euclid_step c m; euclidN k p.1 p.2 | |
| /-- | |
| 入力/前提: c m : Nat。 | |
| 主張: `euclidN 0 c m = (c, m)`。 | |
| 内容: 定義の簡約(`rfl`)。 | |
| 証明: 定義展開で示す。 | |
| 役割: 再帰の基底簡約。 | |
| -/ | |
| @[simp] lemma euclidN_zero (c m : Nat) : euclidN 0 c m = (c, m) := rfl | |
| /-- | |
| 入力/前提: k c m : Nat。 | |
| 主張: `euclidN (k+1) c m` の 1 ステップ展開。 | |
| 内容: `euclid_step` を 1 回適用した後の再帰形。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 再帰展開用の補助。 | |
| -/ | |
| lemma euclidN_succ (k c m : Nat) : | |
| euclidN (k + 1) c m = let p := euclid_step c m; euclidN k p.1 p.2 := by | |
| rfl | |
| /-- | |
| 目的: `step` の `(c,m)` を Nat へ落とす補助 `stPairNat` を定義する。 | |
| 定義: `Int.toNat` で `(c,m)` を `(Nat,Nat)` に写す。 | |
| 入力/前提: U : St。 | |
| 出力: 型 `Nat × Nat` の値を返す。 | |
| 役割: `stepN` と `euclidN` の対応付けに使う。 | |
| -/ | |
| def stPairNat (U : St) : Nat × Nat := (Int.toNat U.c, Int.toNat U.m) | |
| /-- | |
| 入力/前提: `U : St`、`h : (step (step U)).c ≠ 0`。 | |
| 主張: `step` の 1 ステップが Euclid 更新に一致する(Nat 版)。 | |
| 内容: `step_after_preprocess_euclid` を `Int.toNat` へ落として示す。 | |
| 証明: 場合分け・式変形で示す。 | |
| 役割: `stepN_eq_euclidN` の橋渡し。 | |
| -/ | |
| lemma step_after_preprocess_euclid_nat (U : St) | |
| (h : (step (step U)).c ≠ 0) : | |
| stPairNat (step (step U)) = | |
| euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2 := by | |
| rcases step_after_preprocess_euclid U h with ⟨hc, hm⟩ | |
| -- `m` が 0 でないこと(`step` の不変条件より) | |
| have hm_nat_ne : (Int.toNat (step U).m) ≠ 0 := by | |
| intro h0 | |
| have hm_le : (step U).m ≤ 0 := (Int.toNat_eq_zero).1 h0 | |
| exact (not_le_of_gt (step U).hm) hm_le | |
| -- `c` の非負性(正規化により `c=0` または `c=m`) | |
| have hc1_nonneg : 0 ≤ (step U).c := by | |
| cases step_c_or U with | |
| | inl h0 => | |
| simp only [h0, le_refl] | |
| | inr h1 => | |
| have hm0 : 0 ≤ U.m := le_of_lt U.hm | |
| rw [h1] | |
| exact hm0 | |
| -- `Int` の `%` を `Nat` の `%` に落とすための補助 | |
| have hmod : | |
| Int.toNat ((step U).c % (step U).m) = | |
| (Int.toNat (step U).c) % (Int.toNat (step U).m) := by | |
| apply Int.ofNat.inj | |
| calc | |
| (Int.toNat ((step U).c % (step U).m) : Int) | |
| = (step U).c % (step U).m := by | |
| exact Int.toNat_of_nonneg (Int.emod_nonneg _ (ne_of_gt (step U).hm)) | |
| _ = | |
| (Int.ofNat (Int.toNat (step U).c)) % | |
| (Int.ofNat (Int.toNat (step U).m)) := by | |
| simp only [Int.ofNat_eq_natCast, Int.toNat_of_nonneg hc1_nonneg, | |
| Int.toNat_of_nonneg (le_of_lt (step U).hm)] | |
| _ = (Int.ofNat ((Int.toNat (step U).c) % (Int.toNat (step U).m))) := by | |
| exact (Int.natCast_mod (Int.toNat (step U).c) (Int.toNat (step U).m)).symm | |
| -- 目的の等式 | |
| ext | |
| · have hfst : | |
| (euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2).1 = | |
| Int.toNat (step U).m := by | |
| simp only [euclid_step, stPairNat, hm_nat_ne, ↓reduceDIte] | |
| calc | |
| Int.toNat (step (step U)).c = Int.toNat (step U).m := by | |
| rw [hc] | |
| _ = (euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2).1 := by | |
| symm | |
| exact hfst | |
| · have hsnd : | |
| (euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2).2 = | |
| (Int.toNat (step U).c) % (Int.toNat (step U).m) := by | |
| simp only [euclid_step, stPairNat, hm_nat_ne, ↓reduceDIte] | |
| calc | |
| Int.toNat (step (step U)).m = Int.toNat ((step U).c % (step U).m) := by | |
| rw [hm] | |
| _ = (Int.toNat (step U).c) % (Int.toNat (step U).m) := hmod | |
| _ = (euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2).2 := by | |
| symm | |
| exact hsnd | |
| /-- | |
| 入力/前提: `U : St`、`t : Nat`、`hStay : ∀ i, i ≤ t → (stepN i (step U)).c ≠ 0`。 | |
| 主張: `c ≠ 0` の間、`stepN` と `euclidN` の反復が一致する。 | |
| 内容: `step U` を初期状態とし、`t` 回の反復一致を帰納法で示す。 | |
| 証明: 帰納法・既存補題の書き換えで示す。 | |
| 役割: Euclid 反復による停止上界評価に使う。 | |
| -/ | |
| lemma stepN_eq_euclidN (U : St) (t : Nat) | |
| (hStay : ∀ i, i ≤ t → (stepN i (step U)).c ≠ 0) : | |
| stPairNat (stepN t (step U)) = | |
| euclidN t (stPairNat (step U)).1 (stPairNat (step U)).2 := by | |
| induction t generalizing U with | |
| | zero => | |
| simp only [stPairNat, stepN, step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, | |
| normS, normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, euclidN] | |
| | succ t ih => | |
| have h1 : (step (step U)).c ≠ 0 := by | |
| have h1' : (1 : Nat) ≤ t + 1 := Nat.succ_le_succ (Nat.zero_le _) | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite, ne_eq, stepN] using hStay 1 h1' | |
| have hstep : | |
| stPairNat (step (step U)) = | |
| euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2 := | |
| step_after_preprocess_euclid_nat U h1 | |
| have hStay' : ∀ i, i ≤ t → (stepN i (step (step U))).c ≠ 0 := by | |
| intro i hi | |
| have hi' : i + 1 ≤ t + 1 := Nat.succ_le_succ hi | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite, ne_eq, stepN] using hStay (i + 1) hi' | |
| have ih' : | |
| stPairNat (stepN t (step (step U))) = | |
| euclidN t (stPairNat (step (step U))).1 (stPairNat (step (step U))).2 := | |
| ih (U := step U) hStay' | |
| have ih'' : | |
| stPairNat (stepN t (step (step U))) = | |
| euclidN t | |
| (euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2).1 | |
| (euclid_step (stPairNat (step U)).1 (stPairNat (step U)).2).2 := by | |
| simpa only [hstep] using ih' | |
| simpa only [stepN, step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, | |
| normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite, euclidN_succ] using ih'' | |
| /-- | |
| 入力/前提: `U : St`、`k : Nat`、`hStay : ∀ i, i ≤ k + 1 → (stepN i U).c ≠ 0`。 | |
| 主張: `c ≠ 0` が `k+1` 回続くなら、`step U` から `k` 回も `c ≠ 0` が続く。 | |
| 内容: `i+1` の不変性を `stepN` 展開で `i` に落とす。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `stepN_eq_euclidN` の前提を作る補助。 | |
| -/ | |
| lemma stepN_stay_from_succ (U : St) (k : Nat) | |
| (hStay : ∀ i, i ≤ k + 1 → (stepN i U).c ≠ 0) : | |
| ∀ i, i ≤ k → (stepN i (step U)).c ≠ 0 := by | |
| intro i hi | |
| have hi' : i + 1 ≤ k + 1 := Nat.succ_le_succ hi | |
| have h := hStay (i + 1) hi' | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, normC, | |
| zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite, ne_eq, stepN] using h | |
| /-- | |
| 入力/前提: i j : Nat、U : St。 | |
| 主張: `stepN (i + j) U = stepN j (stepN i U)`。 | |
| 内容: `i` による帰納法で `stepN` の再帰を展開する。 | |
| 証明: 帰納法で示す。 | |
| 役割: 反復の分割・再結合に使う。 | |
| -/ | |
| lemma stepN_add (i j : Nat) (U : St) : | |
| stepN (i + j) U = stepN j (stepN i U) := by | |
| induction i generalizing U with | |
| | zero => | |
| simp only [zero_add, stepN] | |
| | succ i ih => | |
| simp only [Nat.succ_add, Nat.succ_eq_add_one, stepN, step, step_reduce, stnorm_y, Yn1, yOf, | |
| zfloorDiv, step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, | |
| Int.max_assoc, step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, ih] | |
| /-- | |
| 入力/前提: `U : St`、`k i : Nat`、`hk : (stepN k U).c ≠ 0`、`hi : i ≤ k`。 | |
| 主張: `(stepN k U).c ≠ 0` なら任意の `i ≤ k` で `(stepN i U).c ≠ 0`。 | |
| 内容: `stepN_add` と `stepN_c_zero_of_c_zero` を用いた反証法。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 途中段階の非停止性を引き継ぐ補助。 | |
| -/ | |
| lemma stepN_nonzero_of_le (U : St) (k i : Nat) | |
| (hk : (stepN k U).c ≠ 0) (hi : i ≤ k) : | |
| (stepN i U).c ≠ 0 := by | |
| intro hzero | |
| have hEq : stepN k U = stepN (k - i) (stepN i U) := by | |
| simpa only [Nat.add_sub_of_le hi] using (stepN_add i (k - i) U) | |
| have hzero' : (stepN (k - i) (stepN i U)).c = 0 := | |
| stepN_c_zero_of_c_zero (k - i) (stepN i U) hzero | |
| have hk0 : (stepN k U).c = 0 := by | |
| simpa only [hEq] using hzero' | |
| exact hk hk0 | |
| /-- | |
| 入力/前提: c m n : Nat、h : m <= n。 | |
| 主張: `m ≤ n` なら `(euclidN n c m).2 = 0`。 | |
| 内容: `n` による帰納法と `euclid_step` の定義で示す。 | |
| 証明: 帰納法・場合分け・既存補題の書き換えで示す。 | |
| 役割: Euclid 反復の停止上界に使う。 | |
| -/ | |
| lemma euclidN_c_zero_of_le (c m n : Nat) (h : m <= n) : | |
| (euclidN n c m).2 = 0 := by | |
| induction n generalizing c m with | |
| | zero => | |
| have hm : m = 0 := Nat.eq_zero_of_le_zero h | |
| subst hm | |
| simp only [euclidN] | |
| | succ n ih => | |
| by_cases hm0 : m = 0 | |
| case pos => | |
| subst hm0 | |
| have h0 := ih (c := c) (m := 0) (Nat.zero_le n) | |
| simpa only [euclidN_succ, euclid_step, ↓reduceDIte] using h0 | |
| case neg => | |
| have hm_pos : 0 < m := Nat.pos_of_ne_zero hm0 | |
| have hr_lt : c % m < m := Nat.mod_lt _ hm_pos | |
| have hr_le_n : c % m <= n := by | |
| have hlt : c % m < n + 1 := lt_of_lt_of_le hr_lt h | |
| exact (Nat.lt_succ_iff).1 hlt | |
| have ih' := ih (c := m) (m := c % m) hr_le_n | |
| simpa only [euclidN_succ, euclid_step, hm0, ↓reduceDIte] using ih' | |
| /-- | |
| 入力/前提: i j c m : Nat。 | |
| 主張: `euclidN (i + j) c m = let p := euclidN i c m; euclidN j p.1 p.2`。 | |
| 内容: `i` による帰納法で `euclidN` を展開する。 | |
| 証明: 帰納法で示す。 | |
| 役割: Euclid 反復の分割・再結合に使う。 | |
| -/ | |
| lemma euclidN_add (i j c m : Nat) : | |
| euclidN (i + j) c m = | |
| let p := euclidN i c m; euclidN j p.1 p.2 := by | |
| induction i generalizing c m with | |
| | zero => | |
| simp only [zero_add, euclidN] | |
| | succ i ih => | |
| simp only [Nat.succ_add, Nat.succ_eq_add_one, euclidN_succ, ih] | |
| /-- | |
| 入力/前提: t c m : Nat、h : m = 0。 | |
| 主張: `m=0` なら任意回数の `euclidN` でも第2成分は 0。 | |
| 内容: `t` による帰納法と `euclid_step` の定義で示す。 | |
| 証明: 帰納法で示す。 | |
| 役割: Euclid 反復の停止不変性。 | |
| -/ | |
| lemma euclidN_c_zero_of_c_zero (t c m : Nat) (h : m = 0) : | |
| (euclidN t c m).2 = 0 := by | |
| induction t generalizing c m with | |
| | zero => | |
| simp only [euclidN, h] | |
| | succ t ih => | |
| simp only [h, euclidN_succ, euclid_step, ↓reduceDIte, ih] | |
| /-- | |
| 入力/前提: `c m k i : Nat`、`hk : (euclidN k c m).2 ≠ 0`、`hi : i ≤ k`。 | |
| 主張: `(euclidN k c m).2 ≠ 0` なら任意の `i ≤ k` で `(euclidN i c m).2 ≠ 0`。 | |
| 内容: `euclidN_add` と `euclidN_c_zero_of_c_zero` を用いた反証法。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: Euclid 反復の非停止性を引き継ぐ補助。 | |
| -/ | |
| lemma euclidN_nonzero_of_le (c m k i : Nat) | |
| (hk : (euclidN k c m).2 ≠ 0) (hi : i ≤ k) : | |
| (euclidN i c m).2 ≠ 0 := by | |
| intro hzero | |
| have hEq : euclidN k c m = let p := euclidN i c m; euclidN (k - i) p.1 p.2 := by | |
| simpa only [Nat.add_sub_of_le hi] using (euclidN_add i (k - i) c m) | |
| have hzero' : (euclidN (k - i) (euclidN i c m).1 (euclidN i c m).2).2 = 0 := | |
| euclidN_c_zero_of_c_zero (k - i) (euclidN i c m).1 (euclidN i c m).2 hzero | |
| have hk0 : (euclidN k c m).2 = 0 := by | |
| simpa only [hEq] using hzero' | |
| exact hk hk0 | |
| /-- | |
| 入力/前提: `c m k : Nat`、`hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0`。 | |
| 主張: `euclidN` が `k` 回続いて停止しないなら `fib (k+2) ≤ m`。 | |
| 内容: 強い帰納法で Euclid 反復の下界を示す。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: `euclidN_c_zero_of_lt_fib` の反証に使う。 | |
| -/ | |
| lemma euclidN_fib_lower (c m k : Nat) | |
| (hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0) : | |
| Nat.fib (k + 2) ≤ m := by | |
| revert c m hStay | |
| refine Nat.strong_induction_on k ?_ | |
| intro k ih c m hStay | |
| cases k with | |
| | zero => | |
| have hm : m ≠ 0 := hStay 0 (Nat.zero_le _) | |
| have hmpos : 0 < m := Nat.pos_of_ne_zero hm | |
| simpa only [zero_add, Nat.fib_two, ge_iff_le, Nat.succ_eq_add_one] using | |
| (Nat.succ_le_iff).2 hmpos | |
| | succ k0 => | |
| have hm0 : m ≠ 0 := hStay 0 (Nat.zero_le _) | |
| have h1 : (euclidN 1 c m).2 ≠ 0 := hStay 1 (Nat.succ_le_succ (Nat.zero_le _)) | |
| have hr1_ne : c % m ≠ 0 := by | |
| simpa only [ne_eq, euclidN_succ, euclid_step, hm0, ↓reduceDIte, euclidN_zero] using h1 | |
| set r1 : Nat := c % m | |
| have hStay1 : ∀ i, i ≤ k0 → (euclidN i m r1).2 ≠ 0 := by | |
| intro i hi | |
| have h := hStay (i + 1) (Nat.succ_le_succ hi) | |
| simpa only [ne_eq, euclidN_succ, euclid_step, hm0, ↓reduceDIte] using h | |
| have hr1_lower : Nat.fib (k0 + 2) ≤ r1 := | |
| ih k0 (Nat.lt_succ_self k0) m r1 hStay1 | |
| cases k0 with | |
| | zero => | |
| have hmpos : 0 < m := Nat.pos_of_ne_zero hm0 | |
| have hr1_lt : r1 < m := by | |
| simpa only [r1] using (Nat.mod_lt c hmpos) | |
| have h1lt : 1 < m := lt_of_le_of_lt hr1_lower hr1_lt | |
| have h2le : 2 ≤ m := Nat.succ_le_of_lt h1lt | |
| simpa only [zero_add, Nat.reduceAdd, Nat.fib_add_two, Nat.fib_one, Nat.fib_zero, | |
| ge_iff_le] using h2le | |
| | succ k1 => | |
| set r2 : Nat := m % r1 | |
| have hr1_ne' : r1 ≠ 0 := by | |
| simpa only [ne_eq, r1] using hr1_ne | |
| have hStay2 : ∀ i, i ≤ k1 → (euclidN i r1 r2).2 ≠ 0 := by | |
| intro i hi | |
| have hi' : i + 2 ≤ k1 + 2 := Nat.add_le_add_right hi 2 | |
| have h := hStay (i + 2) (by | |
| simpa only [Nat.add_comm, Nat.add_left_comm, Nat.reduceAdd, | |
| add_le_add_iff_right] using hi') | |
| simpa only [ne_eq, euclidN_succ, euclid_step, hm0, ↓reduceDIte, hr1_ne', r1] using h | |
| have hr2_lower : Nat.fib (k1 + 2) ≤ r2 := | |
| ih k1 (Nat.lt_succ_of_lt (Nat.lt_succ_self k1)) r1 r2 hStay2 | |
| -- m ≥ r1 + r2 | |
| have hr1_pos : 0 < r1 := Nat.pos_of_ne_zero hr1_ne' | |
| have hmpos : 0 < m := Nat.pos_of_ne_zero hm0 | |
| have hr1_lt : r1 < m := by | |
| simpa only [r1] using (Nat.mod_lt c hmpos) | |
| have hr1_le : r1 ≤ m := Nat.le_of_lt hr1_lt | |
| have hdivpos : 0 < m / r1 := Nat.div_pos hr1_le hr1_pos | |
| have hq_ge : 1 ≤ m / r1 := (Nat.succ_le_iff).2 hdivpos | |
| have hmul_ge : r1 ≤ r1 * (m / r1) := by | |
| simpa only [mul_one] using (Nat.mul_le_mul_left r1 hq_ge) | |
| have hsum_le : r1 + r2 ≤ r1 * (m / r1) + r2 := | |
| Nat.add_le_add_right hmul_ge r2 | |
| have hmod : r2 + r1 * (m / r1) = m := by | |
| simpa only using (Nat.mod_add_div m r1) | |
| have hsum_le' : r1 + r2 ≤ m := by | |
| have hmod' : r1 * (m / r1) + r2 = m := by | |
| simpa only [Nat.add_comm] using hmod | |
| exact hsum_le.trans_eq hmod' | |
| -- fib (k1+4) ≤ r1 + r2 | |
| have hfib_le : Nat.fib (k1 + 4) ≤ r1 + r2 := by | |
| have hsum : Nat.fib (k1 + 3) + Nat.fib (k1 + 2) ≤ r1 + r2 := | |
| Nat.add_le_add hr1_lower hr2_lower | |
| calc | |
| Nat.fib (k1 + 4) = Nat.fib (k1 + 3) + Nat.fib (k1 + 2) := by | |
| simpa only [Nat.add_assoc, Nat.add_comm, Nat.add_left_comm, Nat.reduceAdd] using | |
| (Nat.fib_add_two (n := k1 + 2)) | |
| _ ≤ r1 + r2 := hsum | |
| exact hfib_le.trans hsum_le' | |
| /-- | |
| 入力/前提: `c m k : Nat`、`hcm : m < c`、 | |
| `hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0`。 | |
| 主張: 第2成分が `k` 回まで 0 にならず、かつ初期値で `m<c` なら | |
| `fib (k+3) ≤ c`。 | |
| 内容: `fib (k+2) ≤ m` と、1段ずらした列から得る `fib (k+1) ≤ c%m` を加え、 | |
| `c = m*(c/m) + (c%m)`(かつ `c/m ≥ 1`)で上から押さえる。 | |
| 証明: `k=0` と `k>0` の場合分け、および既存補題 `euclidN_fib_lower` の合成。 | |
| 役割: `stepBoundOfM = greatestFib-1` で `step` 側停止上界を示すための強化補題。 | |
| -/ | |
| lemma euclidN_fib_lower_first_of_lt (c m k : Nat) | |
| (hcm : m < c) | |
| (hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0) : | |
| Nat.fib (k + 3) ≤ c := by | |
| cases k with | |
| | zero => | |
| have hm_ne : m ≠ 0 := hStay 0 (Nat.zero_le _) | |
| have hm_pos : 0 < m := Nat.pos_of_ne_zero hm_ne | |
| have h1_le_m : 1 ≤ m := Nat.succ_le_of_lt hm_pos | |
| have h1_lt_c : 1 < c := lt_of_le_of_lt h1_le_m hcm | |
| have h2_le_c : 2 ≤ c := Nat.succ_le_of_lt h1_lt_c | |
| calc | |
| Nat.fib (0 + 3) = Nat.fib 3 := by simp | |
| _ = 2 := by decide | |
| _ ≤ c := h2_le_c | |
| | succ k0 => | |
| have hm_ne : m ≠ 0 := hStay 0 (Nat.zero_le _) | |
| have hm_pos : 0 < m := Nat.pos_of_ne_zero hm_ne | |
| set r1 : Nat := c % m | |
| have hStay1 : ∀ i, i ≤ k0 → (euclidN i m r1).2 ≠ 0 := by | |
| intro i hi | |
| have h := hStay (i + 1) (Nat.succ_le_succ hi) | |
| simpa only [euclidN_succ, euclid_step, hm_ne, ↓reduceDIte, r1] using h | |
| have hm_lower : Nat.fib (k0 + 3) ≤ m := by | |
| have htmp : Nat.fib (Nat.succ k0 + 2) ≤ m := | |
| euclidN_fib_lower c m (Nat.succ k0) hStay | |
| simpa only [Nat.succ_eq_add_one, Nat.add_assoc, Nat.add_comm, Nat.add_left_comm] using htmp | |
| have hr1_lower : Nat.fib (k0 + 2) ≤ r1 := | |
| euclidN_fib_lower m r1 k0 hStay1 | |
| have hfib_le_sum : Nat.fib (k0 + 4) ≤ m + r1 := by | |
| have hsum : Nat.fib (k0 + 3) + Nat.fib (k0 + 2) ≤ m + r1 := | |
| Nat.add_le_add hm_lower hr1_lower | |
| calc | |
| Nat.fib (k0 + 4) = Nat.fib (k0 + 3) + Nat.fib (k0 + 2) := by | |
| simpa only [Nat.add_assoc, Nat.add_comm, Nat.add_left_comm, Nat.reduceAdd] using | |
| (Nat.fib_add_two (n := k0 + 2)) | |
| _ ≤ m + r1 := hsum | |
| have hdiv_pos : 0 < c / m := Nat.div_pos (Nat.le_of_lt hcm) hm_pos | |
| have hq_ge1 : 1 ≤ c / m := Nat.succ_le_of_lt hdiv_pos | |
| have hmul_ge : m ≤ m * (c / m) := by | |
| calc | |
| m = m * 1 := by simp | |
| _ ≤ m * (c / m) := Nat.mul_le_mul_left m hq_ge1 | |
| have hsum_le : m + r1 ≤ m * (c / m) + r1 := | |
| Nat.add_le_add_right hmul_ge r1 | |
| have hmod : r1 + m * (c / m) = c := by | |
| simpa only [r1] using (Nat.mod_add_div c m) | |
| have hsum_le_c : m + r1 ≤ c := by | |
| have hmod' : m * (c / m) + r1 = c := by | |
| simpa only [Nat.add_comm] using hmod | |
| exact hsum_le.trans_eq hmod' | |
| calc | |
| Nat.fib (Nat.succ k0 + 3) = Nat.fib (k0 + 4) := by | |
| simp only [Nat.succ_eq_add_one, Nat.add_assoc] | |
| _ ≤ m + r1 := hfib_le_sum | |
| _ ≤ c := hsum_le_c | |
| /-- | |
| 入力/前提: `c m k : Nat`、`h : m < Nat.fib (k + 2)`。 | |
| 主張: `m < fib (k+2)` なら `(euclidN k c m).2 = 0`。 | |
| 内容: 反証法で `euclidN_fib_lower` を用いて `fib (k+2) ≤ m` と矛盾させる。 | |
| 証明: 反証法・既存補題の書き換えで示す。 | |
| 役割: Fibonacci による Euclid 反復の停止上界。 | |
| -/ | |
| lemma euclidN_c_zero_of_lt_fib (c m k : Nat) | |
| (h : m < Nat.fib (k + 2)) : | |
| (euclidN k c m).2 = 0 := by | |
| by_contra hk | |
| have hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0 := by | |
| intro i hi | |
| exact euclidN_nonzero_of_le c m k i hk hi | |
| have hlower : Nat.fib (k + 2) ≤ m := euclidN_fib_lower c m k hStay | |
| exact (not_lt_of_ge hlower) h | |
| /-- | |
| 入力/前提: `c m : Nat`。 | |
| 主張: ある時刻 `t` で Euclid 反復の第2成分は 0 になる。 | |
| 内容: `t = m` を取れば `m ≤ m` から `euclidN_c_zero_of_le` が使える。 | |
| 証明: 具体的証人 `m` を与える。 | |
| 役割: `euclidTau`(`Nat.find`)の存在仮定。 | |
| -/ | |
| lemma euclidN_exists_c_zero (c m : Nat) : | |
| ∃ t, (euclidN t c m).2 = 0 := by | |
| refine ⟨m, ?_⟩ | |
| exact euclidN_c_zero_of_le c m m (Nat.le_refl m) | |
| /-- | |
| 目的: Euclid 反復の最小停止時刻 `euclidTau` を定義する。 | |
| 定義: `(euclidN t c m).2 = 0` を満たす `t` の最小値(`Nat.find`)。 | |
| 入力/前提: `c m : Nat`。 | |
| 出力: 型 `Nat` の値を返す。 | |
| 役割: tex で用いる停止時刻 `\tau` の Lean 側対応物。 | |
| -/ | |
| def euclidTau (c m : Nat) : Nat := | |
| Nat.find (euclidN_exists_c_zero c m) | |
| /-- | |
| 入力/前提: `c m : Nat`。 | |
| 主張: `euclidTau c m` で Euclid 反復の第2成分は 0 になる。 | |
| 内容: `Nat.find_spec` を展開して停止性を得る。 | |
| 証明: `Nat.find` の仕様。 | |
| 役割: 停止時刻の到達性を保証する基本補題。 | |
| -/ | |
| lemma euclidTau_spec (c m : Nat) : | |
| (euclidN (euclidTau c m) c m).2 = 0 := by | |
| exact Nat.find_spec (euclidN_exists_c_zero c m) | |
| /-- | |
| 入力/前提: `c m i j : Nat`、`hij : i ≤ j`、`hi0 : (euclidN i c m).2 = 0`。 | |
| 主張: ある時刻で第2成分が 0 なら、以降の時刻でも第2成分は 0。 | |
| 内容: `euclidN_add` で分解し、後半は `euclidN_c_zero_of_c_zero` を適用する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 停止性の単調性(後方不変性)。 | |
| -/ | |
| lemma euclidN_c_zero_of_le_index (c m i j : Nat) (hij : i ≤ j) | |
| (hi0 : (euclidN i c m).2 = 0) : | |
| (euclidN j c m).2 = 0 := by | |
| have hEq : euclidN j c m = let p := euclidN i c m; euclidN (j - i) p.1 p.2 := by | |
| simpa only [Nat.add_sub_of_le hij] using (euclidN_add i (j - i) c m) | |
| have htail : (euclidN (j - i) (euclidN i c m).1 (euclidN i c m).2).2 = 0 := | |
| euclidN_c_zero_of_c_zero (j - i) (euclidN i c m).1 (euclidN i c m).2 hi0 | |
| simpa only [hEq] using htail | |
| /-- | |
| 入力/前提: `c m t : Nat`、`ht : (euclidN t c m).2 = 0`。 | |
| 主張: `euclidTau c m ≤ t`。 | |
| 内容: `Nat.find_min'` で最小性を得る。 | |
| 証明: `Nat.find` の最小性。 | |
| 役割: 停止時刻の最小性を与える。 | |
| -/ | |
| lemma euclidTau_le_of_c_zero (c m t : Nat) | |
| (ht : (euclidN t c m).2 = 0) : | |
| euclidTau c m ≤ t := by | |
| exact Nat.find_min' (euclidN_exists_c_zero c m) ht | |
| /-- | |
| 入力/前提: `c m t : Nat`、`ht : t < euclidTau c m`。 | |
| 主張: `t` は最小停止時刻より前なので `(euclidN t c m).2 ≠ 0`。 | |
| 内容: 反証法で `euclidTau_le_of_c_zero` と矛盾させる。 | |
| 証明: 反証法。 | |
| 役割: 停止時刻より前では未停止であることを示す。 | |
| -/ | |
| lemma euclidTau_nonzero_of_lt (c m t : Nat) (ht : t < euclidTau c m) : | |
| (euclidN t c m).2 ≠ 0 := by | |
| intro hz | |
| have hle : euclidTau c m ≤ t := euclidTau_le_of_c_zero c m t hz | |
| exact (Nat.not_lt_of_ge hle) ht | |
| /-- | |
| 入力/前提: `c m k : Nat`。 | |
| 主張: `euclidTau c m ≤ k` と `(euclidN k c m).2 = 0` は同値。 | |
| 内容: 前向きは停止性の単調性、後向きは `Nat.find` の最小性。 | |
| 証明: 既存補題の合成。 | |
| 役割: tex での「`\tau \le k`」と Lean の停止判定を接続する基礎同値。 | |
| -/ | |
| lemma euclidTau_le_iff_c_zero (c m k : Nat) : | |
| euclidTau c m ≤ k ↔ (euclidN k c m).2 = 0 := by | |
| constructor | |
| · intro hle | |
| exact euclidN_c_zero_of_le_index c m (euclidTau c m) k hle (euclidTau_spec c m) | |
| · intro hk0 | |
| exact euclidTau_le_of_c_zero c m k hk0 | |
| /-- | |
| 入力/前提: `c m k : Nat`、`h : m < Nat.fib (k + 2)`。 | |
| 主張: `m < fib (k+2)` なら `euclidTau c m ≤ k`。 | |
| 内容: `euclidN_c_zero_of_lt_fib` で `k` 時刻停止を得て最小性を適用する。 | |
| 証明: 既存補題の合成。 | |
| 役割: tex の補題 `lem:euclid_classic` に対応する停止時刻版。 | |
| -/ | |
| lemma euclidTau_le_of_lt_fib (c m k : Nat) | |
| (h : m < Nat.fib (k + 2)) : | |
| euclidTau c m ≤ k := by | |
| exact euclidTau_le_of_c_zero c m k (euclidN_c_zero_of_lt_fib c m k h) | |
| /-- | |
| 入力/前提: `c m : Nat`、`hm : 0 < m`。 | |
| 主張: `m > 0` なら最小停止時刻 `euclidTau c m` は `Nat.greatestFib m - 1` 以下。 | |
| 内容: `m < fib (greatestFib m + 1)` を `k := greatestFib m - 1` の形に直し、 | |
| `euclidTau_le_of_lt_fib` を適用する。 | |
| 証明: `Nat.lt_fib_greatestFib_add_one`、`Nat.le_greatestFib`、`omega` を合成する。 | |
| 役割: tex の「Euclid 反復は高々 `g(m_0)-1` 回で停止」に対応する Lean 側補題。 | |
| -/ | |
| lemma euclidTau_le_greatestFib_pred (c m : Nat) (hm : 0 < m) : | |
| euclidTau c m ≤ Nat.greatestFib m - 1 := by | |
| have hfib1_le : Nat.fib 1 ≤ m := by | |
| simpa using (Nat.succ_le_of_lt hm) | |
| have hg_ge1 : 1 ≤ Nat.greatestFib m := | |
| (Nat.le_greatestFib (m := 1) (n := m)).2 hfib1_le | |
| have hlt1 : m < Nat.fib (Nat.greatestFib m + 1) := | |
| Nat.lt_fib_greatestFib_add_one m | |
| have hidx : (Nat.greatestFib m - 1) + 2 = Nat.greatestFib m + 1 := by | |
| omega | |
| have hlt2 : m < Nat.fib ((Nat.greatestFib m - 1) + 2) := by | |
| simpa only [hidx] using hlt1 | |
| exact euclidTau_le_of_lt_fib c m (Nat.greatestFib m - 1) hlt2 | |
| /-- | |
| 入力/前提: `c m : Nat`、`hm : 0 < m`。 | |
| 主張: `stepBoundOfM m` は最小停止時刻 `euclidTau c m` の上界。 | |
| 内容: `stepBoundOfM = Nat.greatestFib - 1` を使って `euclidTau_le_greatestFib_pred` に帰着する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 実装上の反復上界 `stepBoundOfM` と厳密停止時刻評価を接続する。 | |
| -/ | |
| lemma euclidTau_le_stepBoundOfM (c m : Nat) (hm : 0 < m) : | |
| euclidTau c m ≤ stepBoundOfM m := by | |
| simpa only [stepBoundOfM, Fib.greatestFibIter_eq_greatestFib] using | |
| (euclidTau_le_greatestFib_pred c m hm) | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `stepBoundOfM (Int.toNat U.m)` 回 `step` を適用すれば `c=0` に到達する。 | |
| 内容: 非停止を仮定し、`step` と Euclid 反復の対応から | |
| 強化補題 `euclidN_fib_lower_first_of_lt` を適用して矛盾を得る。 | |
| 証明: 反証法・既存補題の書き換えで示す。 | |
| 役割: 反復回数の上界保証(停止の証明)。 | |
| 注意: `U.m` は `Int` なので `Int.toNat` を使う(`U.hm : 0 < U.m` より妥当)。 | |
| -/ | |
| theorem stepN_bound_c_zero (U : St) : | |
| (stepN (stepBoundOfM (Int.toNat U.m)) U).c = 0 := by | |
| set m0 : Nat := Int.toNat U.m | |
| set g : Nat := Nat.greatestFib m0 | |
| have hm0_ne : m0 ≠ 0 := by | |
| intro h0 | |
| have hnat0 : Int.toNat U.m = 0 := by simpa only [m0] using h0 | |
| have hle : U.m ≤ 0 := (Int.toNat_eq_zero).1 hnat0 | |
| exact (not_le_of_gt U.hm) hle | |
| have hm0_pos : 0 < m0 := Nat.pos_of_ne_zero hm0_ne | |
| have hm0_ge1 : 1 ≤ m0 := Nat.succ_le_of_lt hm0_pos | |
| have hfib2_le : Nat.fib 2 ≤ m0 := by | |
| simpa only [Nat.fib_two] using hm0_ge1 | |
| have hg_ge2 : 2 ≤ g := by | |
| simpa only [g] using (Nat.le_greatestFib (m := 2) (n := m0)).2 hfib2_le | |
| have hk : stepBoundOfM m0 = g - 1 := by | |
| simp only [stepBoundOfM, Fib.greatestFibIter_eq_greatestFib, g] | |
| by_contra hnonzero | |
| have hk_non : (stepN (g - 1) U).c ≠ 0 := by | |
| simpa only [m0, hk, ne_eq] using hnonzero | |
| have hStayU : ∀ i, i ≤ g - 1 → (stepN i U).c ≠ 0 := by | |
| intro i hi | |
| exact stepN_nonzero_of_le U (g - 1) i hk_non hi | |
| have hStayStep : ∀ i, i ≤ g - 2 → (stepN i (step U)).c ≠ 0 := by | |
| apply stepN_stay_from_succ U (g - 2) | |
| intro i hi | |
| have hi' : i ≤ g - 1 := by omega | |
| exact hStayU i hi' | |
| have hstep_c_ne : (step U).c ≠ 0 := by | |
| have h0 := hStayStep 0 (Nat.zero_le _) | |
| simpa only [stepN] using h0 | |
| have hdec : (step U).m < U.m := by | |
| cases mwf_step_reduce_reduction U with | |
| | inl h => exact h | |
| | inr h => exact False.elim (hstep_c_ne h) | |
| have hdec_nat : Int.toNat (step U).m < m0 := by | |
| have htmp : Int.toNat (step U).m < Int.toNat U.m := | |
| (Int.toNat_lt_toNat U.hm).2 hdec | |
| simpa only [m0] using htmp | |
| have hstep_c_eq : (step U).c = U.m := by | |
| cases step_c_or U with | |
| | inl hc0 => exact False.elim (hstep_c_ne hc0) | |
| | inr hc1 => exact hc1 | |
| have hEq : | |
| stPairNat (stepN (g - 2) (step U)) = | |
| euclidN (g - 2) (stPairNat (step U)).1 (stPairNat (step U)).2 := | |
| stepN_eq_euclidN U (g - 2) hStayStep | |
| have hstepN_m_ne0 : Int.toNat (stepN (g - 2) (step U)).m ≠ 0 := by | |
| intro h0 | |
| have hle : (stepN (g - 2) (step U)).m ≤ 0 := (Int.toNat_eq_zero).1 h0 | |
| exact (not_le_of_gt (stepN (g - 2) (step U)).hm) hle | |
| have hEuclid_non : | |
| (euclidN (g - 2) (stPairNat (step U)).1 (stPairNat (step U)).2).2 ≠ 0 := by | |
| intro hz0 | |
| have hsndEq : | |
| (stPairNat (stepN (g - 2) (step U))).2 = | |
| (euclidN (g - 2) (stPairNat (step U)).1 (stPairNat (step U)).2).2 := by | |
| exact congrArg Prod.snd hEq | |
| exact hstepN_m_ne0 (hsndEq.trans hz0) | |
| have hStayEuclid : | |
| ∀ i, i ≤ g - 2 → | |
| (euclidN i (stPairNat (step U)).1 (stPairNat (step U)).2).2 ≠ 0 := by | |
| intro i hi | |
| exact euclidN_nonzero_of_le (stPairNat (step U)).1 (stPairNat (step U)).2 (g - 2) i | |
| hEuclid_non hi | |
| have hcm : | |
| (stPairNat (step U)).2 < (stPairNat (step U)).1 := by | |
| simpa only [stPairNat, hstep_c_eq, m0] using hdec_nat | |
| have hFib_le : | |
| Nat.fib ((g - 2) + 3) ≤ (stPairNat (step U)).1 := | |
| euclidN_fib_lower_first_of_lt | |
| (stPairNat (step U)).1 (stPairNat (step U)).2 (g - 2) hcm hStayEuclid | |
| have hidx : (g - 2) + 3 = g + 1 := by omega | |
| have hFib_le_m0 : Nat.fib (g + 1) ≤ m0 := by | |
| have h' : Nat.fib (g + 1) ≤ (stPairNat (step U)).1 := by | |
| simpa only [hidx] using hFib_le | |
| simpa only [stPairNat, hstep_c_eq, m0] using h' | |
| have hlt_m0 : m0 < Nat.fib (g + 1) := by | |
| simpa only [g] using (Nat.lt_fib_greatestFib_add_one m0) | |
| exact (Nat.not_lt.mpr hFib_le_m0) hlt_m0 | |
| /-- | |
| 入力/前提: `k : Nat`、`U : St`、`h : (stepN (k + 1) U).c = 0`。 | |
| 主張: `stepN (k+1)` で停止が保証されるなら `mwf_iter_aux (k+1) U` は評価式の最大値を返す。 | |
| 内容: `k` による帰納法と `mwf_step_equiv`・停止枝の評価で示す。 | |
| 証明: 帰納法・場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `mwf_iter_correct` の中核補題。 | |
| -/ | |
| lemma mwf_iter_aux_correct (k : Nat) (U : St) | |
| (h : (stepN (k + 1) U).c = 0) : | |
| mwf_iter_aux (k + 1) U = max U.r (U.s + st_mwf U) := by | |
| induction k generalizing U with | |
| | zero => | |
| by_cases h0 : U.c = 0 | |
| · calc | |
| mwf_iter_aux 1 U = (step U).r := by simp only [mwf_iter_aux, h0, ↓reduceDIte, step, | |
| step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, normC, | |
| zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] | |
| _ = max U.r (U.s + st_mwf U) := by | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, | |
| normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, st_mwf, mwf, img, obj, | |
| dom] using (mwf_step_reduce_result U h0).symm | |
| · have h1 : (step U).c = 0 := by | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, | |
| normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, stepN] using h | |
| have hstepEq : | |
| max U.r (U.s + st_mwf U) = | |
| max (step U).r ((step U).s + st_mwf (step U)) := by | |
| simpa only [st_mwf, mwf, img, obj, zfloorDiv, dom, step, step_reduce, stnorm_y, Yn1, yOf, | |
| step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] using (mwf_step_equiv U) | |
| have hY0 : stnorm_y (step_normalize U) = 0 := | |
| stnorm_y_step_normalize_eq_zero_of_step_c_zero U h1 | |
| have hstep : | |
| step U = step_reduce_y0 (step_normalize U) hY0 := by | |
| unfold step | |
| exact step_reduce_eq_y0 (step_normalize U) hY0 | |
| have hs : (step U).s = (step U).r := by | |
| rw [hstep] | |
| simp only [step_reduce_y0, step_normalize, normS, zfloorDiv, normA, normC, zfloorMod, | |
| normD, Int.max_assoc] | |
| have hmwf0 : st_mwf (step U) = 0 := by | |
| rw [hstep] | |
| exact st_mwf_step_reduce_y0_zero (step_normalize U) hY0 | |
| have htail : | |
| max (step U).r ((step U).s + st_mwf (step U)) = (step U).r := by | |
| rw [hs, hmwf0] | |
| simp only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, | |
| normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite, add_zero, max_self] | |
| calc | |
| mwf_iter_aux 1 U = (step U).r := by simp only [mwf_iter_aux, h0, ↓reduceDIte, step, | |
| step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, normA, normC, | |
| zfloorMod, normD, step_reduce_y0, Int.max_assoc, step_reduce_ypos_a_nonneg, | |
| step_reduce_ypos_a_neg, dite_eq_ite] | |
| _ = max (step U).r ((step U).s + st_mwf (step U)) := htail.symm | |
| _ = max U.r (U.s + st_mwf U) := hstepEq.symm | |
| | succ k ih => | |
| by_cases h0 : U.c = 0 | |
| · calc | |
| mwf_iter_aux (Nat.succ (Nat.succ k)) U = (step U).r := by | |
| simp only [mwf_iter_aux, h0, ↓reduceDIte, step, step_reduce, stnorm_y, Yn1, yOf, | |
| zfloorDiv, step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, | |
| Int.max_assoc, step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] | |
| _ = max U.r (U.s + st_mwf U) := by | |
| simpa only [step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, normS, | |
| normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, st_mwf, mwf, img, obj, | |
| dom] using (mwf_step_reduce_result U h0).symm | |
| · have h' : (stepN (k + 1) (step U)).c = 0 := by | |
| simpa only [stepN, step, step_reduce, stnorm_y, Yn1, yOf, zfloorDiv, step_normalize, | |
| normS, normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] using h | |
| have hIH : | |
| mwf_iter_aux (k + 1) (step U) = | |
| max (step U).r ((step U).s + st_mwf (step U)) := | |
| ih (U := step U) h' | |
| have hstepEq : | |
| max U.r (U.s + st_mwf U) = | |
| max (step U).r ((step U).s + st_mwf (step U)) := by | |
| simpa only [st_mwf, mwf, img, obj, zfloorDiv, dom, step, step_reduce, stnorm_y, Yn1, yOf, | |
| step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, Int.max_assoc, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] using (mwf_step_equiv U) | |
| calc | |
| mwf_iter_aux (Nat.succ (Nat.succ k)) U = | |
| mwf_iter_aux (k + 1) (step U) := by | |
| simp only [mwf_iter_aux, h0, ↓reduceDIte, step, step_reduce, stnorm_y, Yn1, yOf, | |
| zfloorDiv, step_normalize, normS, normA, normC, zfloorMod, normD, step_reduce_y0, | |
| Int.max_assoc, step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite] | |
| _ = max (step U).r ((step U).s + st_mwf (step U)) := hIH | |
| _ = max U.r (U.s + st_mwf U) := hstepEq.symm | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 反復実装 `mwf_iter` は定義的な `mwf` と一致する。 | |
| 内容: `stepN_bound_c_zero` と `mwf_iter_aux_correct` を組み合わせて示す。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: 実装の正しさ保証。 | |
| -/ | |
| theorem mwf_iter_correct | |
| (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| mwf_iter N M A B C D hN hM = mwf N M A B C D hN hM := by | |
| let U : St := St.mk (B * zfloorDiv D M hM) 0 N M A B C D hN hM | |
| set k : Nat := stepBoundOfM (Int.toNat M) | |
| have hbound : (stepN k U).c = 0 := by | |
| simpa only using (stepN_bound_c_zero U) | |
| have hkpos : 0 < k := by | |
| have hMnat_ne : Int.toNat M ≠ 0 := by | |
| intro h0 | |
| have hle : M ≤ 0 := (Int.toNat_eq_zero).1 h0 | |
| exact (not_le_of_gt hM) hle | |
| have hMnat_pos : 0 < Int.toNat M := Nat.pos_of_ne_zero hMnat_ne | |
| have hMnat_ge1 : 1 ≤ Int.toNat M := Nat.succ_le_of_lt hMnat_pos | |
| have hfib2_le : Nat.fib 2 ≤ Int.toNat M := by | |
| simpa only [Nat.fib_two] using hMnat_ge1 | |
| have hg_ge2 : 2 ≤ Nat.greatestFib (Int.toNat M) := | |
| (Nat.le_greatestFib (m := 2) (n := Int.toNat M)).2 hfib2_le | |
| have hk_ge1' : 1 ≤ stepBoundOfM (Int.toNat M) := by | |
| unfold stepBoundOfM | |
| rw [Fib.greatestFibIter_eq_greatestFib] | |
| omega | |
| have hk_ge1 : 1 ≤ k := by | |
| simpa only [k] using hk_ge1' | |
| exact (Nat.succ_le_iff).1 hk_ge1 | |
| have hinit : max U.r (U.s + st_mwf U) = mwf N M A B C D hN hM := by | |
| simpa only [zfloorDiv, st_mwf, U, mwf, img, obj, dom, zero_add, sup_eq_right] using | |
| (mwf_step_init_equiv N M A B C D hN hM).symm | |
| cases hk : k with | |
| | zero => | |
| simp only [hk, lt_self_iff_false] at hkpos | |
| | succ k' => | |
| have h' : (stepN (k' + 1) U).c = 0 := by | |
| simpa only [hk, k] using hbound | |
| have hcorrect : | |
| mwf_iter_aux (k' + 1) U = | |
| max U.r (U.s + st_mwf U) := | |
| mwf_iter_aux_correct k' U h' | |
| have hcorrect' : | |
| mwf_iter_aux k U = | |
| max U.r (U.s + st_mwf U) := by | |
| simpa only [hk] using hcorrect | |
| simpa only [mwf_iter, hk, zfloorDiv, mwf_iter_aux, step, step_reduce, stnorm_y, Yn1, yOf, | |
| step_normalize, normS, zero_add, normA, normC, zfloorMod, normD, step_reduce_y0, max_self, | |
| step_reduce_ypos_a_nonneg, step_reduce_ypos_a_neg, dite_eq_ite, mwf, img, obj, dom, k, | |
| U] using hcorrect'.trans hinit | |
| /-- | |
| 入力/前提: l r m a b c d : Int、hLR : l < r、hM : 0 < m。 | |
| 主張: 区間版 `mwfLr_iter` は定義的な `mwfLr` と一致する。 | |
| 内容: 置換・商剰余分解で `mwf_iter_correct` に還元する。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 区間版反復実装の正しさ保証。 | |
| -/ | |
| theorem mwfLr_iter_collect | |
| (l r m a b c d : Int) (hLR : l < r) (hM : 0 < m) : | |
| mwfLr_iter l r m a b c d hLR hM = | |
| mwfLr l r m a b c d hLR hM := by | |
| classical | |
| have hN : 0 < r - l := by nlinarith [hLR] | |
| let n : Int := r - l | |
| let q : Int := zfloorDiv (c * l + d) m hM | |
| let d' : Int := zfloorMod (c * l + d) m hM | |
| let cst : Int := a * l + b * q | |
| let f : Int → Int := fun x => cst + x | |
| have hm0 : m ≠ 0 := ne_of_gt hM | |
| have hqd : c * l + d = m * q + d' := by | |
| simpa only [q, d', mul_comm, add_comm, zfloorDiv, zfloorMod] using | |
| (Int.emod_add_mul_ediv (c * l + d) m).symm | |
| have hdiv : | |
| ∀ t : Int, | |
| zfloorDiv (c * (l + t) + d) m hM = | |
| q + zfloorDiv (c * t + d') m hM := by | |
| intro t | |
| unfold zfloorDiv | |
| calc | |
| (c * (l + t) + d) / m = (c * t + (c * l + d)) / m := by ring_nf | |
| _ = (c * t + (m * q + d')) / m := by simp only [hqd] | |
| _ = (c * t + d' + m * q) / m := by ring_nf | |
| _ = (c * t + d') / m + q := by | |
| simpa only [add_comm, add_left_comm] using | |
| (Int.add_mul_ediv_left (a := c * t + d') (b := m) (c := q) hm0) | |
| _ = q + (c * t + d') / m := by ac_rfl | |
| _ = q + zfloorDiv (c * t + d') m hM := by rfl | |
| have hobj : | |
| ∀ t : Int, | |
| obj a b c d m (l + t) hM = | |
| cst + obj a b c d' m t hM := by | |
| intro t | |
| unfold obj | |
| calc | |
| a * (l + t) + b * zfloorDiv (c * (l + t) + d) m hM | |
| = a * l + a * t + b * zfloorDiv (c * (l + t) + d) m hM := by ring_nf | |
| _ = a * l + a * t + b * (q + zfloorDiv (c * t + d') m hM) := by | |
| rw [hdiv t] | |
| _ = a * l + b * q + (a * t + b * zfloorDiv (c * t + d') m hM) := by ring_nf | |
| _ = cst + obj a b c d' m t hM := by simp only [zfloorDiv, add_left_comm, add_assoc, obj, cst] | |
| have hdom : | |
| domLr l r hLR = (dom n hN).image (fun t => l + t) := by | |
| ext x; constructor | |
| · intro hx | |
| have hx' : l ≤ x ∧ x ≤ r - 1 := by | |
| simpa only [Order.le_sub_one_iff] using (Finset.mem_Icc.mp hx) | |
| refine Finset.mem_image.mpr ?_ | |
| refine ⟨x - l, ?_, by ring_nf⟩ | |
| have h0 : 0 ≤ x - l := by exact sub_nonneg.mpr hx'.1 | |
| have h1 : x - l ≤ n - 1 := by nlinarith [hx'.2] | |
| simpa only [dom, Finset.mem_Icc, Int.sub_nonneg, Order.le_sub_one_iff] using | |
| (Finset.mem_Icc.mpr ⟨h0, h1⟩) | |
| · intro hx | |
| rcases Finset.mem_image.mp hx with ⟨t, ht, rfl⟩ | |
| have ht' : 0 ≤ t ∧ t ≤ n - 1 := by | |
| simpa only [Order.le_sub_one_iff] using (Finset.mem_Icc.mp ht) | |
| have h0 : l ≤ l + t := by nlinarith [ht'.1] | |
| have h1 : l + t ≤ r - 1 := by nlinarith [ht'.2] | |
| exact Finset.mem_Icc.mpr ⟨h0, h1⟩ | |
| have himg : | |
| imgLr l r m a b c d hLR hM = | |
| (dom n hN).image (fun t => cst + obj a b c d' m t hM) := by | |
| calc | |
| imgLr l r m a b c d hLR hM = | |
| (domLr l r hLR).image (fun x => obj a b c d m x hM) := by rfl | |
| _ = ((dom n hN).image (fun t => l + t)).image (fun x => obj a b c d m x hM) := by | |
| rw [hdom] | |
| _ = (dom n hN).image ((fun x => obj a b c d m x hM) ∘ fun t => l + t) := by | |
| rw [Finset.image_image] | |
| _ = (dom n hN).image (fun t => obj a b c d m (l + t) hM) := by rfl | |
| _ = (dom n hN).image (fun t => cst + obj a b c d' m t hM) := by | |
| refine Finset.image_congr ?_ | |
| intro t ht | |
| exact hobj t | |
| let S : Finset Int := img n m a b c d' hN hM | |
| have hS : S.Nonempty := by | |
| simpa only [S, img, obj, zfloorDiv, dom, Finset.image_nonempty, Finset.nonempty_Icc, | |
| Int.sub_nonneg] using | |
| (img_nonempty (N := n) (M := m) (A := a) (B := b) (C := c) (D := d') hN hM) | |
| have max'_congr {s t : Finset Int} (hs : s.Nonempty) (ht : t.Nonempty) (h : s = t) : | |
| s.max' hs = t.max' ht := by | |
| cases h | |
| have hproof : hs = ht := by | |
| apply Subsingleton.elim | |
| cases hproof | |
| rfl | |
| have himgS : | |
| (dom n hN).image (fun t => cst + obj a b c d' m t hM) = S.image f := by | |
| dsimp only [obj, zfloorDiv, dom, img, f, S] | |
| symm | |
| rw [Finset.image_image] | |
| rfl | |
| have hmono : Monotone f := by | |
| intro x y hxy | |
| dsimp only [f] | |
| linarith | |
| have hmax : | |
| (S.image f).max' (hS.image f) = cst + S.max' hS := by | |
| simpa only [add_comm, Finset.image_add_right, neg_add_rev, add_assoc] using | |
| (Monotone.map_finset_max' (s := S) (f := f) hmono hS).symm | |
| have hmwfLr : | |
| mwfLr l r m a b c d hLR hM = (S.image f).max' (hS.image f) := by | |
| dsimp only [mwfLr, imgLr, obj, zfloorDiv, domLr] | |
| have hne : (imgLr l r m a b c d hLR hM).Nonempty := | |
| imgLr_nonempty (L := l) (R := r) (M := m) (A := a) (B := b) | |
| (C := c) (D := d) hLR hM | |
| have hne1 : | |
| ((dom n hN).image (fun t => cst + obj a b c d' m t hM)).Nonempty := | |
| (dom_nonempty hN).image (fun t => cst + obj a b c d' m t hM) | |
| have hne2 : (S.image f).Nonempty := hS.image f | |
| have hne2' : (S.image f).Nonempty := by | |
| rw [←himgS] | |
| exact hne1 | |
| have hmax1 : | |
| (imgLr l r m a b c d hLR hM).max' hne = | |
| ((dom n hN).image (fun t => cst + obj a b c d' m t hM)).max' hne1 := | |
| max'_congr hne hne1 himg | |
| have hmax2 : | |
| ((dom n hN).image (fun t => cst + obj a b c d' m t hM)).max' hne1 = | |
| (S.image f).max' hne2' := | |
| max'_congr hne1 hne2' himgS | |
| have hmax3 : (S.image f).max' hne2' = (S.image f).max' hne2 := by | |
| have hproof : hne2' = hne2 := by | |
| apply Subsingleton.elim | |
| cases hproof | |
| rfl | |
| exact hmax1.trans (hmax2.trans hmax3) | |
| -- assemble | |
| have hiter : | |
| mwfLr_iter l r m a b c d hLR hM = | |
| cst + mwf_iter n m a b c d' hN hM := by | |
| simp only [mwfLr_iter, zfloorDiv, zfloorMod, cst, q, n, d'] | |
| have hiter' : | |
| mwf_iter n m a b c d' hN hM = mwf n m a b c d' hN hM := | |
| mwf_iter_correct (N := n) (M := m) (A := a) (B := b) (C := c) (D := d') hN hM | |
| have hmwf : | |
| mwf n m a b c d' hN hM = S.max' hS := by | |
| simp only [mwf, img, obj, zfloorDiv, dom, S] | |
| calc | |
| mwfLr_iter l r m a b c d hLR hM | |
| = cst + mwf_iter n m a b c d' hN hM := hiter | |
| _ = cst + mwf n m a b c d' hN hM := by simp only [hiter', mwf, img, obj, zfloorDiv, dom] | |
| _ = cst + S.max' hS := by rw [hmwf] | |
| _ = (S.image f).max' (hS.image f) := by | |
| simpa only using hmax.symm | |
| _ = mwfLr l r m a b c d hLR hM := by | |
| simpa only [mwfLr, imgLr, obj, zfloorDiv, domLr] using hmwfLr.symm | |
| end | |
| /- | |
| floor_prod に基づく枠組み(sssec:mwf_floor_prod)の | |
| Lean 側スケルトンをまとめるセクション。 | |
| -/ | |
| namespace FloorProd | |
| /-- | |
| 目的: floor_prod 反復の内部状態を保持する。 | |
| フィールド: `n,m,a,b,x,y,pre,suf` を保持する。 | |
| 不変条件: 本スケルトンでは `Nat` の除算/剰余を使い、必要条件は定理側へ委譲する。 | |
| 役割: `floorProd` 実装(while 反復相当)の中間状態表現。 | |
| -/ | |
| structure LoopState (α : Type _) where | |
| n : Nat | |
| m : Nat | |
| a : Nat | |
| b : Nat | |
| x : α | |
| y : α | |
| pre : α | |
| suf : α | |
| /-- | |
| 目的: floor_prod の数式仕様を定義する。 | |
| 定義: `a,b` を先に `divmod` 正規化してから、sssec:mwf_floor_prod の再帰式を適用する。 | |
| 入力/前提: `n,m,a,b : Nat`, `[Monoid α]`, 要素 `x,y`。 | |
| 出力: モノイド要素を返す。 | |
| 役割: 実装 `floorProd` の正しさ証明で比較する仕様(tex の流れに合わせた版)。 | |
| -/ | |
| def floorProdSpec {α : Type _} [Monoid α] (n m a b : Nat) (x y : α) : α := | |
| if _hM0 : m = 0 then | |
| x ^ n | |
| else | |
| let p := a / m | |
| let a' := a % m | |
| let x' := x * y ^ p | |
| let q := b / m | |
| let b' := b % m | |
| let pre := y ^ q | |
| let yMax := a' * n + b' | |
| if _hY : yMax < m then | |
| pre * (x' ^ n) | |
| else | |
| pre * | |
| (floorProdSpec (yMax / m - 1) a' m (m + a' - b' - 1) y x' | |
| * y * x' ^ ((yMax % m) / a')) | |
| termination_by m | |
| decreasing_by | |
| have hm : 0 < m := Nat.pos_of_ne_zero _hM0 | |
| exact Nat.mod_lt _ hm | |
| /-- | |
| 目的: floor_prod の while 反復(燃料付き)を定義する。 | |
| 定義: Python 実装の更新式を `fuel` 回まで展開する。 | |
| 入力/前提: `[Monoid α]`, `fuel : Nat`, `st : LoopState α`。 | |
| 出力: 計算結果(モノイド要素)を返す。 | |
| 役割: `floorProd` の本体(停止性は `fuel` で制御)。 | |
| -/ | |
| def floorProdLoop {α : Type _} [Monoid α] : Nat → LoopState α → α | |
| | 0, st => st.pre * (st.x ^ st.n) * st.suf | |
| | fuel + 1, st => | |
| let p := st.a / st.m | |
| let a' := st.a % st.m | |
| let x' := st.x * (st.y ^ p) | |
| let q := st.b / st.m | |
| let b' := st.b % st.m | |
| let pre' := st.pre * (st.y ^ q) | |
| let c' := (a' * st.n + b') / st.m | |
| if c' = 0 then | |
| pre' * (x' ^ st.n) * st.suf | |
| else | |
| let d := ((st.m * c' - b' - 1) / a') + 1 | |
| let suf' := st.y * (x' ^ (st.n - d)) * st.suf | |
| let st' : LoopState α := | |
| { n := c' - 1 | |
| m := a' | |
| a := st.m | |
| b := st.m - b' - 1 + a' | |
| x := st.y | |
| y := x' | |
| pre := pre' | |
| suf := suf' } | |
| floorProdLoop fuel st' | |
| /-- | |
| 目的: floor_prod 実装エントリを定義する。 | |
| 定義: `sssec:mwf_floor_prod` の while 更新式を `floorProdLoop` で実行する。 | |
| 入力/前提: `n,m,a,b : Nat`, `[Monoid α]`, 要素 `x,y`。 | |
| 出力: floor_prod の計算結果を返す。 | |
| 役割: floor_prod の実装本体(`floorProd_correct` の左辺)。 | |
| -/ | |
| def floorProd {α : Type _} [Monoid α] (n m a b : Nat) (x y : α) : α := | |
| let st : LoopState α := | |
| { n := n, m := m, a := a, b := b, x := x, y := y, pre := 1, suf := 1 } | |
| floorProdLoop (stepBoundOfM m) st | |
| /-- | |
| 入力/前提: a m : Nat。 | |
| 主張: `stepBoundOfM m` 回の Euclid 反復で第2成分は 0 になる。 | |
| 内容: `m>0` では `euclidTau ≤ stepBoundOfM` と `euclidTau_le_iff_c_zero` を使い、 | |
| `m=0` は自明に処理する。 | |
| 証明: 場合分けと既存停止時刻補題の合成で示す。 | |
| 役割: floor_prod の fuel 十分性(`a,m` 縮約側)の中核補題。 | |
| -/ | |
| lemma euclidN_second_zero_stepBoundOfM (a m : Nat) : | |
| (euclidN (stepBoundOfM m) a m).2 = 0 := by | |
| by_cases hm : 0 < m | |
| · exact (euclidTau_le_iff_c_zero a m (stepBoundOfM m)).1 | |
| (euclidTau_le_stepBoundOfM a m hm) | |
| · have hm0 : m = 0 := Nat.eq_zero_of_not_pos hm | |
| subst hm0 | |
| exact euclidN_c_zero_of_le a 0 (stepBoundOfM 0) (Nat.zero_le _) | |
| /-- | |
| 入力/前提: n m a b : Nat、hM : 0 < m、ha : a % m = 0。 | |
| 主張: `a' = a % m` が 0 なら `c' = floor((a' * n + b')/m)` は 0。 | |
| 内容: `b' = b % m < m` を使って除算値 0 を示す。 | |
| 証明: 式変形と `Nat.div_eq_of_lt` で示す。 | |
| 役割: floor_prod ループの停止判定 `c' = 0` の直接トリガー補題。 | |
| -/ | |
| lemma floorProd_cprime_zero_of_aModZero | |
| (n m a b : Nat) (hM : 0 < m) (ha : a % m = 0) : | |
| ((a % m) * n + (b % m)) / m = 0 := by | |
| rw [ha, zero_mul, zero_add] | |
| exact Nat.div_eq_of_lt (Nat.mod_lt b hM) | |
| /-- | |
| 入力/前提: st : LoopState α。 | |
| 主張: `stepBoundOfM st.m` は `a,m` の Euclid 縮約を 0 余りまで到達させる。 | |
| 内容: `euclidN_second_zero_stepBoundOfM` の状態版。 | |
| 証明: 既存補題の直接適用。 | |
| 役割: `floorProd` に `stepBoundOfM m` を使ってよい根拠(縮約回数側)。 | |
| -/ | |
| theorem floorProdLoop_fuel_sufficient | |
| {α : Type _} [Monoid α] (st : LoopState α) : | |
| (euclidN (stepBoundOfM st.m) st.a st.m).2 = 0 := by | |
| simpa only using (euclidN_second_zero_stepBoundOfM st.a st.m) | |
| /-- | |
| 証明スケッチ: | |
| - `0 ≤ a,b < m` と `a*n+b < m` からすべての差分指数が 0 であることを示す。 | |
| - したがって積は `x` のみを `n` 回掛けた `x^n` に簡約される。 | |
| 入力/前提: `m>0`, `a<m`, `b<m`, `a*n+b<m`。 | |
| 主張: 停止分岐における `floorProdSpec` の閉形式。 | |
| 内容: sssec:mwf_floor_prod の再帰式第1分岐に対応。 | |
| 役割: `floorProd_correct` の基底ケース。 | |
| -/ | |
| theorem floorProdSpec_stop | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (_hM : 0 < m) (_hA : a < m) (_hB : b < m) | |
| (x y : α) (hY : a * n + b < m) : | |
| floorProdSpec n m a b x y = x ^ n := by | |
| have hm0 : m ≠ 0 := Nat.ne_of_gt _hM | |
| have ha_div : a / m = 0 := Nat.div_eq_of_lt _hA | |
| have hb_div : b / m = 0 := Nat.div_eq_of_lt _hB | |
| have ha_mod : a % m = a := Nat.mod_eq_of_lt _hA | |
| have hb_mod : b % m = b := Nat.mod_eq_of_lt _hB | |
| conv_lhs => unfold floorProdSpec | |
| simp only [hm0, ↓reduceDIte, ha_mod, hb_mod, hY, hb_div, pow_zero, ha_div, mul_one, one_mul] | |
| /-- | |
| 証明スケッチ: | |
| - `0 ≤ a,b < m` かつ `m ≤ a*n+b` の下で、格子路の折り返しに対応する再帰式を展開する。 | |
| - `d := ⌊(m*c-b-1)/a⌋+1` と変数交換 `(n,m,a,b,x,y)` 更新を適用し、第2分岐の式を得る。 | |
| 入力/前提: `m>0`, `a<m`, `b<m`, `0<a`, `m ≤ a*n+b`。 | |
| 主張: 再帰分岐における `floorProdSpec` の等式。 | |
| 内容: sssec:mwf_floor_prod の再帰式第2分岐に対応。 | |
| 役割: `floorProd_correct` の帰納ステップ。 | |
| -/ | |
| theorem floorProdSpec_step | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (_hM : 0 < m) (hA : a < m) (_hB : b < m) (_hApos : 0 < a) | |
| (x y : α) (hY : m ≤ a * n + b) : | |
| floorProdSpec n m a b x y = | |
| let yMax := a * n + b | |
| floorProdSpec (yMax / m - 1) a m (m + a - b - 1) y x | |
| * y * x ^ ((yMax % m) / a) := by | |
| have hm0 : m ≠ 0 := Nat.ne_of_gt _hM | |
| have ha_div : a / m = 0 := Nat.div_eq_of_lt hA | |
| have hb_div : b / m = 0 := Nat.div_eq_of_lt _hB | |
| have ha_mod : a % m = a := Nat.mod_eq_of_lt hA | |
| have hb_mod : b % m = b := Nat.mod_eq_of_lt _hB | |
| have hNotLt : ¬ a * n + b < m := Nat.not_lt.mpr hY | |
| conv_lhs => unfold floorProdSpec | |
| simp only [hm0, ↓reduceDIte, ha_mod, hb_mod, hNotLt, hb_div, pow_zero, ha_div, mul_one, one_mul] | |
| /-- | |
| 証明スケッチ: | |
| - `yMax = a*n+b`, `c = ⌊yMax/m⌋`, `r = yMax mod m` とおく。 | |
| - `d = ⌊(m*c-b-1)/a⌋+1` と `k = ⌊r/a⌋` について、`n-d = k` を示す。 | |
| - 本質は `m*c + r = yMax` と `r = a*k + (r mod a)` を用いた商剰余の比較。 | |
| 入力/前提: `m>0`, `0<a<m`, `0≤b<m`, `m ≤ a*n+b`。 | |
| 主張: floor_prod の while 更新で使う指数 `n-d` は仕様側の `⌊(yMax mod m)/a⌋` と一致。 | |
| 内容: 実装側 `suf` 更新式と仕様側第2分岐の指数を同一視する橋渡し補題。 | |
| 役割: `floorProdLoop_spec_invariant` の `c'≠0` 分岐を閉じる算術コア。 | |
| -/ | |
| lemma floorProd_exponent_bridge | |
| (n m a b : Nat) | |
| (hM : 0 < m) (_hA : a < m) (hB : b < m) (hApos : 0 < a) | |
| (hY : m ≤ a * n + b) : | |
| let c := (a * n + b) / m | |
| let d := ((m * c - b - 1) / a) + 1 | |
| n - d = ((a * n + b) % m) / a := by | |
| dsimp only [Lean.Elab.WF.paramLet] | |
| set y : Nat := a * n + b | |
| set c : Nat := y / m | |
| set r : Nat := y % m | |
| set k : Nat := r / a | |
| set x : Nat := m * c - b | |
| set t : Nat := x - 1 | |
| have hy : m * c + r = y := by | |
| subst c r | |
| simpa only [Nat.add_comm] using (Nat.mod_add_div y m) | |
| have hc_pos : 0 < c := by | |
| by_contra hc0 | |
| have hc0' : c = 0 := Nat.eq_zero_of_not_pos hc0 | |
| have hy_lt : y < m := by | |
| have hdiv0 : y / m = 0 := by simpa only [c, Nat.div_eq_zero_iff] using hc0' | |
| rcases (Nat.div_eq_zero_iff.mp hdiv0) with hm0 | hlt | |
| · exact False.elim ((Nat.ne_of_gt hM) hm0) | |
| · exact hlt | |
| exact (Nat.not_le_of_lt hy_lt) (by simpa only [y] using hY) | |
| have hb_mc : b < m * c := by | |
| have hm_le_mc : m ≤ m * c := by | |
| calc | |
| m = m * 1 := by simp only [mul_one] | |
| _ ≤ m * c := Nat.mul_le_mul_left _ (Nat.succ_le_of_lt hc_pos) | |
| exact lt_of_lt_of_le hB hm_le_mc | |
| have hx_pos : 0 < x := by | |
| simpa only [tsub_pos_iff_lt, x] using (Nat.sub_pos_of_lt hb_mc) | |
| have hmc_sub : x = a * n - r := by | |
| unfold x | |
| omega | |
| have hk_div : r / a = k := by rfl | |
| have hk_bounds : k * a ≤ r ∧ r ≤ k * a + a - 1 := by | |
| simpa only [Nat.mul_comm] using (Nat.div_eq_iff hApos).1 hk_div | |
| rcases hk_bounds with ⟨hk_lo, hk_hi⟩ | |
| have hr_lt_an : r < a * n := by | |
| have : 0 < a * n - r := by | |
| simpa only [tsub_pos_iff_lt, hmc_sub] using hx_pos | |
| exact Nat.sub_pos_iff_lt.mp this | |
| have hk_lt_n : k < n := by | |
| have hk_mul_lt : k * a < n * a := | |
| lt_of_le_of_lt hk_lo | |
| (by | |
| simpa only [Nat.mul_comm] using hr_lt_an) | |
| exact Nat.lt_of_mul_lt_mul_right hk_mul_lt | |
| have hq : t / a = n - k - 1 := by | |
| apply (Nat.div_eq_iff hApos).2 | |
| constructor | |
| · have hk_hi_lt : r < (k + 1) * a := by | |
| have hpred_lt : k * a + a - 1 < k * a + a := by | |
| exact Nat.sub_lt (Nat.add_pos_right _ hApos) (Nat.succ_pos 0) | |
| exact lt_of_le_of_lt hk_hi | |
| (by | |
| simpa only [Nat.add_comm, Nat.succ_mul, tsub_lt_self_iff, add_pos_iff, | |
| CanonicallyOrderedAdd.mul_pos, zero_lt_one, and_true] using hpred_lt) | |
| have hsub_lt : a * n - ((k + 1) * a) < a * n - r := | |
| Nat.sub_lt_sub_left hr_lt_an hk_hi_lt | |
| have hsub_id : n - (k + 1) = n - k - 1 := by omega | |
| have hleft_eq : a * n - ((k + 1) * a) = (n - k - 1) * a := by | |
| calc | |
| a * n - ((k + 1) * a) = (n - (k + 1)) * a := by | |
| simpa only [Nat.mul_comm] using (Nat.sub_mul n (k + 1) a).symm | |
| _ = (n - k - 1) * a := by simp only [hsub_id] | |
| have hx_gt : (n - k - 1) * a < x := by | |
| calc | |
| (n - k - 1) * a = a * n - ((k + 1) * a) := hleft_eq.symm | |
| _ < a * n - r := hsub_lt | |
| _ = x := by simp only [hmc_sub] | |
| have : (n - k - 1) * a ≤ x - 1 := Nat.le_pred_of_lt hx_gt | |
| simpa only [ge_iff_le] using this | |
| · have hx_le : x ≤ (n - k) * a := by | |
| have hsub_le : a * n - r ≤ a * n - (k * a) := Nat.sub_le_sub_left hk_lo (a * n) | |
| have hright_eq : a * n - (k * a) = (n - k) * a := by | |
| simpa only [Nat.mul_comm] using (Nat.sub_mul n k a).symm | |
| calc | |
| x = a * n - r := hmc_sub | |
| _ ≤ a * n - (k * a) := hsub_le | |
| _ = (n - k) * a := hright_eq | |
| have ht_lt_x : t < x := by | |
| unfold t | |
| exact Nat.sub_lt hx_pos (Nat.succ_pos 0) | |
| have ht_lt : t < (n - k) * a := lt_of_lt_of_le ht_lt_x hx_le | |
| have hmul_succ : (n - k) * a = (n - k - 1) * a + a := by | |
| have hnk_pos : 0 < n - k := Nat.sub_pos_of_lt hk_lt_n | |
| have hnk_eq : n - k = Nat.succ (n - k - 1) := by | |
| simpa only [Nat.succ_eq_add_one, Nat.pred_eq_sub_one] using | |
| (Nat.succ_pred_eq_of_pos hnk_pos).symm | |
| rw [hnk_eq] | |
| simp only [Nat.succ_eq_add_one, Nat.succ_mul, Nat.mul_comm, add_tsub_cancel_right] | |
| have ht_lt' : t < (n - k - 1) * a + a := by | |
| simpa only [hmul_succ] using ht_lt | |
| exact Nat.le_pred_of_lt ht_lt' | |
| have hq' : (m * c - b - 1) / a = n - k - 1 := by | |
| simpa only using hq | |
| have hd : ((m * c - b - 1) / a) + 1 = n - k := by | |
| rw [hq'] | |
| omega | |
| calc | |
| n - (((m * c - b - 1) / a) + 1) | |
| = n - (n - k) := by simp only [hd] | |
| _ = k := Nat.sub_sub_self (Nat.le_of_lt hk_lt_n) | |
| _ = ((a * n + b) % m) / a := by simp only [k, r, y] | |
| /-- | |
| 証明スケッチ: | |
| - `fuel` に関する帰納法を行う。 | |
| - 基底 `fuel=0` は `floorProdLoop` の定義展開で `pre * x^n * suf` に帰着する。 | |
| - 帰納段階は `c' = ((a%m)*n + (b%m))/m` で分岐する。 | |
| - `c'=0` 側は `floorProdSpec_stop`(正規化後の停止分岐)で一致。 | |
| - `c'≠0` 側は更新後状態 `st'` に IH を適用し、`floorProdSpec_step` で式を貼り合わせる。 | |
| 入力/前提: `fuel : Nat`, `st : LoopState α`, `0 < st.m`、および Euclid 側の十分燃料条件。 | |
| 主張: `floorProdLoop fuel st` は `st.pre * floorProdSpec ... * st.suf` と一致。 | |
| 内容: while ループと再帰仕様をつなぐ中心不変量。 | |
| 役割: `floorProd_correct` を初期状態へ適用するための主補題。 | |
| -/ | |
| theorem floorProdLoop_spec_invariant | |
| {α : Type _} [Monoid α] : | |
| ∀ fuel (st : LoopState α), | |
| 0 < st.m → | |
| (euclidN fuel st.a st.m).2 = 0 → | |
| floorProdLoop fuel st = | |
| st.pre * floorProdSpec st.n st.m st.a st.b st.x st.y * st.suf := by | |
| intro fuel | |
| induction fuel with | |
| | zero => | |
| intro st hM hFuel | |
| have hm0 : st.m = 0 := by | |
| simpa only [euclidN] using hFuel | |
| exact False.elim ((Nat.ne_of_gt hM) hm0) | |
| | succ fuel ih => | |
| intro st hM hFuel | |
| let p := st.a / st.m | |
| let a' := st.a % st.m | |
| let x' := st.x * st.y ^ p | |
| let q := st.b / st.m | |
| let b' := st.b % st.m | |
| let pre' := st.pre * st.y ^ q | |
| let c' := (a' * st.n + b') / st.m | |
| by_cases hc0 : c' = 0 | |
| · have hm0 : st.m ≠ 0 := Nat.ne_of_gt hM | |
| have hy_lt : a' * st.n + b' < st.m := by | |
| have hdiv0 : (a' * st.n + b') / st.m = 0 := by | |
| simpa only [c', Nat.div_eq_zero_iff] using hc0 | |
| rcases (Nat.div_eq_zero_iff.mp hdiv0) with hzm | hlt | |
| · exact False.elim (hm0 hzm) | |
| · exact hlt | |
| have hSpecStop : | |
| floorProdSpec st.n st.m st.a st.b st.x st.y = st.y ^ q * x' ^ st.n := by | |
| conv_lhs => unfold floorProdSpec | |
| simp only [hm0, ↓reduceDIte, hy_lt, q, x', p, a', b'] | |
| calc | |
| floorProdLoop (fuel + 1) st | |
| = pre' * x' ^ st.n * st.suf := by | |
| simp only [floorProdLoop, hc0, ↓reduceIte, pre', q, x', p, c', a', b'] | |
| _ = st.pre * (st.y ^ q * x' ^ st.n) * st.suf := by | |
| simp only [mul_assoc, pre'] | |
| _ = st.pre * floorProdSpec st.n st.m st.a st.b st.x st.y * st.suf := by | |
| rw [hSpecStop] | |
| · have hm0 : st.m ≠ 0 := Nat.ne_of_gt hM | |
| have hA_lt : a' < st.m := by | |
| simpa only using (Nat.mod_lt st.a hM) | |
| have hB_lt : b' < st.m := by | |
| simpa only using (Nat.mod_lt st.b hM) | |
| have hApos : 0 < a' := by | |
| by_contra hNotPos | |
| have ha0 : a' = 0 := Nat.eq_zero_of_not_pos hNotPos | |
| have ha0' : st.a % st.m = 0 := by | |
| simpa only using ha0 | |
| have hc0' : ((st.a % st.m) * st.n + (st.b % st.m)) / st.m = 0 := by | |
| exact floorProd_cprime_zero_of_aModZero st.n st.m st.a st.b hM ha0' | |
| have : c' = 0 := by | |
| simpa only [c', a', b', Nat.div_eq_zero_iff] using hc0' | |
| exact hc0 this | |
| have hY_ge : st.m ≤ a' * st.n + b' := by | |
| have hNotLt : ¬ a' * st.n + b' < st.m := by | |
| intro hlt | |
| have hdiv0 : (a' * st.n + b') / st.m = 0 := Nat.div_eq_of_lt hlt | |
| have : c' = 0 := by | |
| simpa only [c',Nat.div_eq_zero_iff] using hdiv0 | |
| exact hc0 this | |
| exact Nat.le_of_not_gt hNotLt | |
| have hFuel' : (euclidN fuel st.m a').2 = 0 := by | |
| simpa only [euclidN_succ, euclid_step, hm0, ↓reduceDIte] using hFuel | |
| let d := ((st.m * c' - b' - 1) / a') + 1 | |
| let suf' := st.y * (x' ^ (st.n - d)) * st.suf | |
| let st' : LoopState α := | |
| { n := c' - 1 | |
| m := a' | |
| a := st.m | |
| b := st.m - b' - 1 + a' | |
| x := st.y | |
| y := x' | |
| pre := pre' | |
| suf := suf' } | |
| have hIH : | |
| floorProdLoop fuel st' = | |
| st'.pre * floorProdSpec st'.n st'.m st'.a st'.b st'.x st'.y * st'.suf := by | |
| exact ih st' (by simpa only [st'] using hApos) (by simpa only [st', a'] using hFuel') | |
| have hStep : | |
| floorProdSpec st.n st.m a' b' x' st.y = | |
| let yMax := a' * st.n + b' | |
| floorProdSpec (yMax / st.m - 1) a' st.m (st.m + a' - b' - 1) st.y x' | |
| * st.y * x' ^ ((yMax % st.m) / a') := by | |
| exact floorProdSpec_step st.n st.m a' b' hM hA_lt hB_lt hApos x' st.y hY_ge | |
| have hb_norm : st.m - b' - 1 + a' = st.m + a' - b' - 1 := by | |
| omega | |
| have hExp : st.n - d = ((a' * st.n + b') % st.m) / a' := by | |
| unfold d | |
| simpa only using (floorProd_exponent_bridge st.n st.m a' b' hM hA_lt hB_lt hApos hY_ge) | |
| have hSpecMain : | |
| floorProdSpec st.n st.m st.a st.b st.x st.y = | |
| st.y ^ q * | |
| (floorProdSpec (c' - 1) a' st.m (st.m + a' - b' - 1) st.y x' | |
| * st.y * x' ^ ((a' * st.n + b') % st.m / a')) := by | |
| have hNotLt : ¬ a' * st.n + b' < st.m := Nat.not_lt.mpr hY_ge | |
| conv_lhs => unfold floorProdSpec | |
| simp only [hm0, ↓reduceDIte, hNotLt, Nat.add_mod_mod, q, c', a', b', x', p] | |
| have hLoopStep : | |
| floorProdLoop (fuel + 1) st = | |
| pre' * floorProdSpec (c' - 1) a' st.m (st.m + a' - b' - 1) st.y x' | |
| * (st.y * x' ^ ((a' * st.n + b') % st.m / a') * st.suf) := by | |
| calc | |
| floorProdLoop (fuel + 1) st | |
| = floorProdLoop fuel st' := by | |
| simp only [floorProdLoop, hc0, ↓reduceIte, st', c', a', b', x', p, pre', q, | |
| suf', d] | |
| _ = st'.pre * floorProdSpec st'.n st'.m st'.a st'.b st'.x st'.y * st'.suf := by | |
| exact hIH | |
| _ = pre' * floorProdSpec (c' - 1) a' st.m (st.m + a' - b' - 1) st.y x' | |
| * (st.y * x' ^ (st.n - d) * st.suf) := by | |
| simp only [hb_norm, mul_assoc, suf', st'] | |
| _ = pre' * floorProdSpec (c' - 1) a' st.m (st.m + a' - b' - 1) st.y x' | |
| * (st.y * x' ^ ((a' * st.n + b') % st.m / a') * st.suf) := by | |
| simp only [hExp] | |
| calc | |
| floorProdLoop (fuel + 1) st | |
| = pre' * floorProdSpec (c' - 1) a' st.m (st.m + a' - b' - 1) st.y x' | |
| * (st.y * x' ^ ((a' * st.n + b') % st.m / a') * st.suf) := hLoopStep | |
| _ = st.pre * floorProdSpec st.n st.m st.a st.b st.x st.y * st.suf := by | |
| rw [hSpecMain] | |
| simp only [mul_assoc, pre'] | |
| /-- | |
| 証明スケッチ: | |
| - `floorProdLoop_fuel_sufficient` で `stepBoundOfM st.m` が Euclid 縮約に十分なことを得る。 | |
| - `floorProdLoop_spec_invariant` に代入する。 | |
| 入力/前提: `st : LoopState α`, `0 < st.m`。 | |
| 主張: `stepBoundOfM st.m` 回で `floorProdLoop` は仕様形 `pre * spec * suf` になる。 | |
| 内容: 主不変量を既定 fuel へ具体化した形。 | |
| 役割: `floorProd_correct` 直前の橋渡し補題。 | |
| -/ | |
| theorem floorProdLoop_stepBound_eq_spec | |
| {α : Type _} [Monoid α] (st : LoopState α) (hM : 0 < st.m) : | |
| floorProdLoop (stepBoundOfM st.m) st = | |
| st.pre * floorProdSpec st.n st.m st.a st.b st.x st.y * st.suf := by | |
| have hFuel : (euclidN (stepBoundOfM st.m) st.a st.m).2 = 0 := by | |
| simpa only using (floorProdLoop_fuel_sufficient st) | |
| exact floorProdLoop_spec_invariant (fuel := stepBoundOfM st.m) st hM hFuel | |
| /-- | |
| 証明スケッチ: | |
| - `floorProdLoop` に対して不変量(`pre * spec * suf` 形式)を設定する。 | |
| - `c=0` 分岐で停止し、`c>0` 分岐では `floorProdSpec_step` の再帰式で不変量を保存する。 | |
| - 燃料上界が十分であることを示して初期状態に適用する。 | |
| 入力/前提: `m>0`。 | |
| 主張: 実装 `floorProd` は仕様 `floorProdSpec` と一致する。 | |
| 内容: while 反復と数式定義の同値性。 | |
| 役割: floor_prod 枠組みの中心正当化。 | |
| -/ | |
| theorem floorProd_correct | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (_hM : 0 < m) (x y : α) : | |
| floorProd n m a b x y = floorProdSpec n m a b x y := by | |
| let st : LoopState α := | |
| { n := n, m := m, a := a, b := b, x := x, y := y, pre := 1, suf := 1 } | |
| have hst : 0 < st.m := by | |
| simpa only using _hM | |
| have hmain : | |
| floorProdLoop (stepBoundOfM st.m) st = | |
| st.pre * floorProdSpec st.n st.m st.a st.b st.x st.y * st.suf := by | |
| exact floorProdLoop_stepBound_eq_spec st hst | |
| simpa only [floorProd, st, one_mul, mul_one] using hmain | |
| /-- | |
| 目的: `best` が有効なときに束ねて保持する情報を定義する。 | |
| フィールド: `best, dx, arg`。 | |
| 不変条件: `dx` は `X` 個数、`arg` は最大達成の最小添字を表す。 | |
| 役割: `MwfElem.info?` の `some` 側のペイロード。 | |
| -/ | |
| structure BestInfo where | |
| best : Int | |
| dx : Nat | |
| arg : Nat | |
| deriving Repr, DecidableEq | |
| /-- | |
| 目的: floor_prod で `mwf` の最大値と最小 argmax を運ぶデータを定義する。 | |
| フィールド: `sum, info?`。 | |
| 不変条件: `info? = none` は `best/dx/arg` が無効(未定義)であることを表す。 | |
| 役割: sssec:mwf_floor_prod の `MwfElem` を Lean 化。 | |
| -/ | |
| structure MwfElem where | |
| sum : Int | |
| info? : Option BestInfo := none | |
| deriving Repr, DecidableEq | |
| /-- | |
| 目的: `MwfElem` の単位元を定義する。 | |
| 定義: `sum=0, info?=none`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: `MwfElem` モノイドの単位元。 | |
| -/ | |
| def mwfElemOne : MwfElem := | |
| { sum := 0, info? := none } | |
| /-- | |
| 目的: `MwfElem` の積(連結合成)を定義する。 | |
| 定義: Python 実装の `__mul__` 更新式をそのまま移植する。 | |
| 入力/前提: `lhs rhs : MwfElem`。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: floor_prod で prefix 最大と最小 argmax を合成する核。 | |
| -/ | |
| def mwfElemMul (lhs rhs : MwfElem) : MwfElem := | |
| let ssum := lhs.sum + rhs.sum | |
| match lhs.info?, rhs.info? with | |
| | none, none => | |
| { sum := ssum, info? := none } | |
| | some l, none => | |
| { sum := ssum, info? := some l } | |
| | none, some r => | |
| { sum := ssum | |
| info? := some { best := lhs.sum + r.best, dx := r.dx, arg := r.arg } } | |
| | some l, some r => | |
| let sdx := l.dx + r.dx | |
| let candL := l.best | |
| let candR := lhs.sum + r.best | |
| if candL >= candR then | |
| { sum := ssum, info? := some { best := candL, dx := sdx, arg := l.arg } } | |
| else | |
| { sum := ssum, info? := some { best := candR, dx := sdx, arg := l.dx + r.arg } } | |
| instance : One MwfElem := ⟨mwfElemOne⟩ | |
| instance : Mul MwfElem := ⟨mwfElemMul⟩ | |
| /-- | |
| 証明スケッチ: | |
| - `mwfElemOne` の各フィールドが左単位として作用することを `mwfElemMul` 展開で示す。 | |
| 入力/前提: `u : MwfElem`。 | |
| 主張: `1 * u = u`。 | |
| 内容: `MwfElem` の左単位律。 | |
| 役割: `MwfElem` モノイド公理の一部。 | |
| -/ | |
| theorem mwfElem_one_mul (u : MwfElem) : 1 * u = u := by | |
| change mwfElemMul mwfElemOne u = u | |
| cases u with | |
| | mk s info => | |
| cases info with | |
| | none => | |
| simp only [mwfElemMul, mwfElemOne, zero_add] | |
| | some bi => | |
| cases bi with | |
| | mk best dx arg => | |
| simp only [mwfElemMul, mwfElemOne, zero_add] | |
| /-- | |
| 証明スケッチ: | |
| - `mwfElemOne` の各フィールドが右単位として作用することを `mwfElemMul` 展開で示す。 | |
| 入力/前提: `u : MwfElem`。 | |
| 主張: `u * 1 = u`。 | |
| 内容: `MwfElem` の右単位律。 | |
| 役割: `MwfElem` モノイド公理の一部。 | |
| -/ | |
| theorem mwfElem_mul_one (u : MwfElem) : u * 1 = u := by | |
| change mwfElemMul u mwfElemOne = u | |
| cases u with | |
| | mk s info => | |
| cases info with | |
| | none => | |
| simp only [mwfElemMul, mwfElemOne, add_zero] | |
| | some bi => | |
| cases bi with | |
| | mk best dx arg => | |
| simp only [mwfElemMul, mwfElemOne, add_zero] | |
| private def mwfChooseScore (p q : Int × Nat) : Int × Nat := | |
| if p.1 < q.1 then q else p | |
| private def mwfShiftScore (s : Int) (k : Nat) (p : Int × Nat) : Int × Nat := | |
| (s + p.1, k + p.2) | |
| private def mwfInfoScore (i : BestInfo) : Int × Nat := | |
| (i.best, i.arg) | |
| private def mwfMkInfoFromScore (dx : Nat) (sc : Int × Nat) : BestInfo := | |
| { best := sc.1, dx := dx, arg := sc.2 } | |
| private lemma mwfChooseScore_assoc (a b c : Int × Nat) : | |
| mwfChooseScore (mwfChooseScore a b) c = mwfChooseScore a (mwfChooseScore b c) := by | |
| unfold mwfChooseScore | |
| split_ifs <;> simp_all | |
| all_goals omega | |
| private lemma mwfChooseScore_shift (s : Int) (k : Nat) (p q : Int × Nat) : | |
| mwfShiftScore s k (mwfChooseScore p q) = | |
| mwfChooseScore (mwfShiftScore s k p) (mwfShiftScore s k q) := by | |
| unfold mwfChooseScore mwfShiftScore | |
| split_ifs <;> simp_all | |
| all_goals omega | |
| private lemma mwfShiftScore_comp (s1 s2 : Int) (k1 k2 : Nat) (p : Int × Nat) : | |
| mwfShiftScore s1 k1 (mwfShiftScore s2 k2 p) = | |
| mwfShiftScore (s1 + s2) (k1 + k2) p := by | |
| simp only [mwfShiftScore, Prod.mk.injEq] | |
| omega | |
| private lemma mwfElemMul_some_some | |
| (s1 s2 : Int) (l r : BestInfo) : | |
| mwfElemMul { sum := s1, info? := some l } { sum := s2, info? := some r } = | |
| { sum := s1 + s2 | |
| info? := some (mwfMkInfoFromScore (l.dx + r.dx) | |
| (mwfChooseScore (mwfInfoScore l) (mwfShiftScore s1 l.dx (mwfInfoScore r)))) } := by | |
| unfold mwfElemMul mwfChooseScore mwfShiftScore mwfInfoScore mwfMkInfoFromScore | |
| by_cases hlt : l.best < s1 + r.best | |
| · have hgeFalse : ¬ l.best ≥ s1 + r.best := by omega | |
| simp only [hlt, hgeFalse, ↓reduceIte] | |
| · have hge : l.best ≥ s1 + r.best := by | |
| exact le_of_not_gt hlt | |
| simp only [hlt, hge, ↓reduceIte] | |
| private lemma mwfElemMul_assoc_none_some_some | |
| (su sv sw : Int) (v w : BestInfo) : | |
| mwfElemMul (mwfElemMul { sum := su } { sum := sv, info? := some v }) | |
| { sum := sw, info? := some w } = | |
| mwfElemMul { sum := su } | |
| (mwfElemMul { sum := sv, info? := some v } { sum := sw, info? := some w }) := by | |
| have hleftInner : | |
| mwfElemMul { sum := su } { sum := sv, info? := some v } = | |
| { sum := su + sv | |
| info? := some (mwfMkInfoFromScore v.dx (mwfShiftScore su 0 (mwfInfoScore v))) } := by | |
| simp only [mwfElemMul, mwfMkInfoFromScore, mwfShiftScore, mwfInfoScore, zero_add] | |
| have hrightInner : | |
| mwfElemMul { sum := sv, info? := some v } { sum := sw, info? := some w } = | |
| { sum := sv + sw | |
| info? := some (mwfMkInfoFromScore (v.dx + w.dx) | |
| (mwfChooseScore (mwfInfoScore v) (mwfShiftScore sv v.dx (mwfInfoScore w)))) } := | |
| mwfElemMul_some_some sv sw v w | |
| rw [hleftInner, hrightInner] | |
| repeat rw [mwfElemMul_some_some] | |
| simp only [mwfMkInfoFromScore, mwfInfoScore, Prod.mk.eta, mwfElemMul, MwfElem.mk.injEq, | |
| Option.some.injEq, BestInfo.mk.injEq, true_and] | |
| have hmain : | |
| mwfChooseScore (mwfShiftScore su 0 (mwfInfoScore v)) | |
| (mwfShiftScore (su + sv) v.dx (mwfInfoScore w)) | |
| = mwfShiftScore su 0 | |
| (mwfChooseScore (mwfInfoScore v) (mwfShiftScore sv v.dx (mwfInfoScore w))) := by | |
| calc | |
| mwfChooseScore (mwfShiftScore su 0 (mwfInfoScore v)) | |
| (mwfShiftScore (su + sv) v.dx (mwfInfoScore w)) | |
| = mwfChooseScore (mwfShiftScore su 0 (mwfInfoScore v)) | |
| (mwfShiftScore su 0 (mwfShiftScore sv v.dx (mwfInfoScore w))) := by | |
| simp only [mwfShiftScore_comp, zero_add] | |
| _ = mwfShiftScore su 0 | |
| (mwfChooseScore (mwfInfoScore v) (mwfShiftScore sv v.dx (mwfInfoScore w))) := by | |
| symm | |
| exact | |
| mwfChooseScore_shift su 0 (mwfInfoScore v) | |
| (mwfShiftScore sv v.dx (mwfInfoScore w)) | |
| refine ⟨by omega, ?_, ?_⟩ | |
| · exact congrArg Prod.fst hmain | |
| · simpa only [mwfShiftScore, zero_add] using congrArg Prod.snd hmain | |
| private lemma mwfElemMul_assoc_some_none_some | |
| (su sv sw : Int) (u w : BestInfo) : | |
| mwfElemMul (mwfElemMul { sum := su, info? := some u } { sum := sv }) | |
| { sum := sw, info? := some w } = | |
| mwfElemMul { sum := su, info? := some u } | |
| (mwfElemMul { sum := sv } { sum := sw, info? := some w }) := by | |
| have hleftInner : | |
| mwfElemMul { sum := su, info? := some u } { sum := sv } = | |
| { sum := su + sv, info? := some u } := by | |
| simp only [mwfElemMul] | |
| have hrightInner : | |
| mwfElemMul { sum := sv } { sum := sw, info? := some w } = | |
| { sum := sv + sw | |
| info? := some (mwfMkInfoFromScore w.dx (mwfShiftScore sv 0 (mwfInfoScore w))) } := by | |
| simp only [mwfElemMul, mwfMkInfoFromScore, mwfShiftScore, mwfInfoScore, zero_add] | |
| rw [hleftInner, hrightInner] | |
| repeat rw [mwfElemMul_some_some] | |
| simp only [mwfMkInfoFromScore, mwfInfoScore, Prod.mk.eta, mwfShiftScore_comp, add_zero, | |
| MwfElem.mk.injEq, and_true] | |
| omega | |
| private lemma mwfElemMul_assoc_some_some_none | |
| (su sv sw : Int) (u v : BestInfo) : | |
| mwfElemMul (mwfElemMul { sum := su, info? := some u } { sum := sv, info? := some v }) | |
| { sum := sw } = | |
| mwfElemMul { sum := su, info? := some u } | |
| (mwfElemMul { sum := sv, info? := some v } { sum := sw }) := by | |
| have hleftInner : | |
| mwfElemMul { sum := su, info? := some u } { sum := sv, info? := some v } = | |
| { sum := su + sv | |
| info? := some (mwfMkInfoFromScore (u.dx + v.dx) | |
| (mwfChooseScore (mwfInfoScore u) (mwfShiftScore su u.dx (mwfInfoScore v)))) } := | |
| mwfElemMul_some_some su sv u v | |
| have hrightInner : | |
| mwfElemMul { sum := sv, info? := some v } { sum := sw } = | |
| { sum := sv + sw, info? := some v } := by | |
| simp only [mwfElemMul] | |
| rw [hleftInner, hrightInner] | |
| repeat rw [mwfElemMul_some_some] | |
| simp only [mwfElemMul, mwfMkInfoFromScore, mwfInfoScore, MwfElem.mk.injEq, and_true] | |
| omega | |
| private lemma mwfElemMul_assoc_some_some_some | |
| (su sv sw : Int) (u v w : BestInfo) : | |
| mwfElemMul (mwfElemMul { sum := su, info? := some u } { sum := sv, info? := some v }) | |
| { sum := sw, info? := some w } = | |
| mwfElemMul { sum := su, info? := some u } | |
| (mwfElemMul { sum := sv, info? := some v } { sum := sw, info? := some w }) := by | |
| have huv : | |
| mwfElemMul { sum := su, info? := some u } { sum := sv, info? := some v } = | |
| { sum := su + sv | |
| info? := some (mwfMkInfoFromScore (u.dx + v.dx) | |
| (mwfChooseScore (mwfInfoScore u) (mwfShiftScore su u.dx (mwfInfoScore v)))) } := | |
| mwfElemMul_some_some su sv u v | |
| have hvw : | |
| mwfElemMul { sum := sv, info? := some v } { sum := sw, info? := some w } = | |
| { sum := sv + sw | |
| info? := some (mwfMkInfoFromScore (v.dx + w.dx) | |
| (mwfChooseScore (mwfInfoScore v) (mwfShiftScore sv v.dx (mwfInfoScore w)))) } := | |
| mwfElemMul_some_some sv sw v w | |
| rw [huv, hvw] | |
| repeat rw [mwfElemMul_some_some] | |
| simp only [mwfMkInfoFromScore, mwfInfoScore, Prod.mk.eta, mwfChooseScore_assoc, | |
| mwfChooseScore_shift, mwfShiftScore_comp, MwfElem.mk.injEq, Option.some.injEq, | |
| BestInfo.mk.injEq, and_true, true_and] | |
| omega | |
| /-- | |
| 入力/前提: `u v w : MwfElem`。 | |
| 主張: `mwfElemMul` は結合的。 | |
| 内容: `MwfElem` をモノイドに昇格する主要補題。 | |
| 役割: `floorProd` を `MwfElem` に適用する前提。 | |
| -/ | |
| theorem mwfElem_mul_assoc (u v w : MwfElem) : | |
| (u * v) * w = u * (v * w) := by | |
| change mwfElemMul (mwfElemMul u v) w = mwfElemMul u (mwfElemMul v w) | |
| cases u with | |
| | mk su iu => | |
| cases v with | |
| | mk sv iv => | |
| cases w with | |
| | mk sw iw => | |
| cases iu with | |
| | none => | |
| cases iv with | |
| | none => | |
| cases iw with | |
| | none => | |
| simp only [mwfElemMul, MwfElem.mk.injEq, and_true] | |
| omega | |
| | some wv => | |
| simp only [mwfElemMul, MwfElem.mk.injEq, Option.some.injEq, | |
| BestInfo.mk.injEq, and_self, and_true] | |
| omega | |
| | some vv => | |
| cases iw with | |
| | none => | |
| simp only [mwfElemMul, MwfElem.mk.injEq, and_true] | |
| omega | |
| | some wv => | |
| exact mwfElemMul_assoc_none_some_some su sv sw vv wv | |
| | some uv => | |
| cases iv with | |
| | none => | |
| cases iw with | |
| | none => | |
| simp only [mwfElemMul, MwfElem.mk.injEq, and_true] | |
| omega | |
| | some wv => | |
| exact mwfElemMul_assoc_some_none_some su sv sw uv wv | |
| | some vv => | |
| cases iw with | |
| | none => | |
| exact mwfElemMul_assoc_some_some_none su sv sw uv vv | |
| | some wv => | |
| exact mwfElemMul_assoc_some_some_some su sv sw uv vv wv | |
| instance : Monoid MwfElem where | |
| one := 1 | |
| mul := (· * ·) | |
| one_mul := mwfElem_one_mul | |
| mul_one := mwfElem_mul_one | |
| mul_assoc := mwfElem_mul_assoc | |
| /-- | |
| 目的: `MwfElem.__pow__`(閉形式)に対応する実装を定義する。 | |
| 定義: | |
| - `k = 0` なら単位元 `1` を返す。 | |
| - `k > 0` で `info? = none` なら `sum` のみを `k` 倍し、`info? = none` を保つ。 | |
| - `k > 0` で `info? = some info` の場合: | |
| - `sum > 0` なら `best/arg` を末尾ブロックへシフトした閉形式で更新する。 | |
| - `sum ≤ 0` なら `best/arg` は先頭ブロック値を保持する。 | |
| 入力/前提: `z : MwfElem`, `k : Nat`。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: Python 実装 `__pow__`(sssec:impl_mwf_floor_prod)を Lean 上で表し、正しさ定理で検証する対象。 | |
| -/ | |
| def mwfElemPowImpl (z : MwfElem) (k : Nat) : MwfElem := | |
| match k with | |
| | 0 => 1 | |
| | k + 1 => | |
| let ssum : Int := z.sum * (Nat.succ k) | |
| match z.info? with | |
| | none => | |
| { sum := ssum, info? := none } | |
| | some info => | |
| if z.sum > 0 then | |
| { sum := ssum | |
| info? := some | |
| { best := z.sum * k + info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.dx * k + info.arg } } | |
| else | |
| { sum := ssum | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } | |
| private lemma int_mul_succ (s : Int) (k : Nat) : | |
| s * (Nat.succ k) + s = s * (Nat.succ (Nat.succ k)) := by | |
| calc | |
| s * (Nat.succ k) + s = s * ((Nat.succ k : Int) + 1) := by ring | |
| _ = s * (Nat.succ (Nat.succ k)) := by simp only [Nat.succ_eq_add_one, Nat.cast_add, | |
| Nat.cast_one] | |
| private lemma nat_mul_succ (d : Nat) (k : Nat) : | |
| d * (Nat.succ k) + d = d * (Nat.succ (Nat.succ k)) := by | |
| simpa only [Nat.succ_eq_add_one, Nat.mul_add, mul_one, Nat.add_comm, Nat.add_left_comm, | |
| Nat.reduceAdd] using (Nat.mul_succ d (Nat.succ k)).symm | |
| private lemma mwfElem_pow_none_succ (s : Int) : | |
| ∀ k, ({ sum := s, info? := none } : MwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k), info? := none } | |
| | 0 => by | |
| simp only [Nat.succ_eq_add_one, zero_add, pow_one, Nat.cast_one, mul_one] | |
| | k + 1 => by | |
| calc | |
| ({ sum := s, info? := none } : MwfElem) ^ (Nat.succ (Nat.succ k)) | |
| = (({ sum := s, info? := none } : MwfElem) ^ (Nat.succ k)) * | |
| { sum := s, info? := none } := by | |
| simp only [Nat.succ_eq_add_one, pow_succ] | |
| _ = { sum := s * (Nat.succ k), info? := none } * { sum := s, info? := none } := by | |
| have hpow : ({ sum := s, info? := none } : MwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k), info? := none } := mwfElem_pow_none_succ s k | |
| rw [hpow] | |
| _ = { sum := s * (Nat.succ (Nat.succ k)), info? := none } := by | |
| change mwfElemMul { sum := s * (Nat.succ k), info? := none } | |
| { sum := s, info? := none } = | |
| { sum := s * (Nat.succ (Nat.succ k)), info? := none } | |
| simp only [mwfElemMul, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, | |
| MwfElem.mk.injEq, and_true] | |
| simpa only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using int_mul_succ s k | |
| private lemma mwfElem_pow_some_nonpos_succ (s : Int) (info : BestInfo) (hS : s ≤ 0) : | |
| ∀ k, ({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } | |
| | 0 => by | |
| simp only [Nat.succ_eq_add_one, zero_add, pow_one, Nat.cast_one, mul_one] | |
| | k + 1 => by | |
| have hMulNonPos : s * (Nat.succ k) ≤ 0 := by | |
| exact mul_nonpos_of_nonpos_of_nonneg hS (Int.natCast_nonneg _) | |
| have hge : | |
| info.best ≥ s * (Nat.succ k) + info.best := by | |
| nlinarith [hMulNonPos] | |
| calc | |
| ({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ (Nat.succ k)) | |
| = (({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ k)) * | |
| { sum := s, info? := some info } := by | |
| simp only [Nat.succ_eq_add_one, pow_succ] | |
| _ = { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } * { sum := s, info? := some info } := by | |
| have hpow : | |
| ({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } := mwfElem_pow_some_nonpos_succ s info hS k | |
| rw [hpow] | |
| _ = { sum := s * (Nat.succ (Nat.succ k)) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ (Nat.succ k)) | |
| arg := info.arg } } := by | |
| change mwfElemMul | |
| { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } | |
| { sum := s, info? := some info } = | |
| { sum := s * (Nat.succ (Nat.succ k)) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ (Nat.succ k)) | |
| arg := info.arg } } | |
| have hCond : s * ((k : Int) + 1) ≤ 0 := by | |
| simpa only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using hMulNonPos | |
| simp only [mwfElemMul, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, ge_iff_le, | |
| add_le_iff_nonpos_left, hCond, ↓reduceIte, MwfElem.mk.injEq, Option.some.injEq, | |
| BestInfo.mk.injEq, and_true, true_and] | |
| constructor | |
| · simpa only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using int_mul_succ s k | |
| · simpa only [Nat.succ_eq_add_one] using nat_mul_succ info.dx k | |
| private lemma mwfElem_pow_some_pos_succ (s : Int) (info : BestInfo) (hS : 0 < s) : | |
| ∀ k, ({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := s * k + info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.dx * k + info.arg } } | |
| | 0 => by | |
| simp only [Nat.succ_eq_add_one, zero_add, pow_one, Nat.cast_one, mul_one, CharP.cast_eq_zero, | |
| mul_zero] | |
| | k + 1 => by | |
| have hlt : | |
| s * k + info.best < s * (Nat.succ k) + info.best := by | |
| have hklt : (k : Int) < (Nat.succ k : Int) := by | |
| exact_mod_cast Nat.lt_succ_self k | |
| have hmul : s * (k : Int) < s * (Nat.succ k : Int) := by | |
| exact Int.mul_lt_mul_of_pos_left hklt hS | |
| simpa only [add_comm, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, add_lt_add_iff_left, | |
| gt_iff_lt] using add_lt_add_right hmul info.best | |
| have hnotLe : | |
| ¬ (s * (Nat.succ k) ≤ s * k) := by | |
| exact not_le.mpr (by simpa only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, | |
| add_lt_add_iff_right] using hlt) | |
| calc | |
| ({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ (Nat.succ k)) | |
| = (({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ k)) * | |
| { sum := s, info? := some info } := by | |
| simp only [Nat.succ_eq_add_one, pow_succ] | |
| _ = { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := s * k + info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.dx * k + info.arg } } * { sum := s, info? := some info } := by | |
| have hpow : | |
| ({ sum := s, info? := some info } : MwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := s * k + info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.dx * k + info.arg } } := mwfElem_pow_some_pos_succ s info hS k | |
| rw [hpow] | |
| _ = { sum := s * (Nat.succ (Nat.succ k)) | |
| info? := some | |
| { best := s * (Nat.succ k) + info.best | |
| dx := info.dx * (Nat.succ (Nat.succ k)) | |
| arg := info.dx * (Nat.succ k) + info.arg } } := by | |
| change mwfElemMul | |
| { sum := s * (Nat.succ k) | |
| info? := some | |
| { best := s * k + info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.dx * k + info.arg } } | |
| { sum := s, info? := some info } = | |
| { sum := s * (Nat.succ (Nat.succ k)) | |
| info? := some | |
| { best := s * (Nat.succ k) + info.best | |
| dx := info.dx * (Nat.succ (Nat.succ k)) | |
| arg := info.dx * (Nat.succ k) + info.arg } } | |
| have hnotLe' : ¬ s * ((k : Int) + 1) ≤ s * (k : Int) := by | |
| simpa only [not_le, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using hnotLe | |
| simp only [mwfElemMul, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, ge_iff_le, | |
| add_le_add_iff_right, hnotLe', ↓reduceIte, MwfElem.mk.injEq, Option.some.injEq, | |
| BestInfo.mk.injEq, and_true, true_and] | |
| constructor | |
| · simpa only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using int_mul_succ s k | |
| · simpa only [Nat.succ_eq_add_one] using nat_mul_succ info.dx k | |
| /-- | |
| 入力/前提: `z : MwfElem`, `k : Nat`。 | |
| 主張: `mwfElemPowImpl z k = z ^ k`。 | |
| 内容: 実装 `mwfElemPowImpl`(`__pow__` の閉形式)がモノイド冪と一致することを示す。 | |
| 証明: `k` の場合分け後、`info?` と `sum` の符号で補助補題 | |
| `mwfElem_pow_none_succ` / `mwfElem_pow_some_nonpos_succ` / `mwfElem_pow_some_pos_succ` | |
| を適用する。 | |
| 役割: sssec:impl_mwf_floor_prod の `__pow__` 実装が数理仕様(モノイド冪)に正しいことの検証定理。 | |
| -/ | |
| theorem mwfElemPowImpl_correct (z : MwfElem) (k : Nat) : | |
| mwfElemPowImpl z k = z ^ k := by | |
| cases k with | |
| | zero => | |
| simp only [mwfElemPowImpl, pow_zero] | |
| | succ k => | |
| cases z with | |
| | mk s info? => | |
| cases info? with | |
| | none => | |
| simpa only [mwfElemPowImpl, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using | |
| (mwfElem_pow_none_succ s k).symm | |
| | some info => | |
| by_cases hS : s > 0 | |
| · simpa only [mwfElemPowImpl, gt_iff_lt, hS, ↓reduceIte, Nat.succ_eq_add_one, | |
| Nat.cast_add, Nat.cast_one] using (mwfElem_pow_some_pos_succ s info hS k).symm | |
| · have hSle : s ≤ 0 := le_of_not_gt hS | |
| simpa only [mwfElemPowImpl, gt_iff_lt, hS, ↓reduceIte, Nat.succ_eq_add_one, | |
| Nat.cast_add, Nat.cast_one] using | |
| (mwfElem_pow_some_nonpos_succ s info hSle k).symm | |
| /-- | |
| 目的: `X=(sum=a,info?=some(best=0,dx=1,arg=0))` を定義する。 | |
| 定義: `MwfElem` の初期要素 `X`。 | |
| 入力/前提: `a : Int`。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: sssec:mwf_floor_prod の写像で使う `x` 側モノイド要素。 | |
| -/ | |
| def mwfElemX (a : Int) : MwfElem := | |
| { sum := a, info? := some { best := 0, dx := 1, arg := 0 } } | |
| /-- | |
| 目的: `Y=(sum=b,info?=none)` を定義する。 | |
| 定義: `MwfElem` の初期要素 `Y`。 | |
| 入力/前提: `b : Int`。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: sssec:mwf_floor_prod の写像で使う `y` 側モノイド要素。 | |
| -/ | |
| def mwfElemY (b : Int) : MwfElem := | |
| { sum := b, info? := none } | |
| /-- | |
| 目的: `floorProd` と `mwfElemX/Y` で区間版 `mwf` と最小 `argmax` を同時に計算する。 | |
| 定義: | |
| - 区間 `[L,R)` を `t` による `[0,n)`(`n = R-L`)へ平行移動する。 | |
| - `C` と `CL+D` を `ediv/emod` 正規化し、`floorProd n m c' d' X Y` を評価する。 | |
| - `X = mwfElemX (A + B*⌊C/M⌋)`, `Y = mwfElemY B` を用いる。 | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 出力: 型 `MwfLrArgResult` の値を返す。 | |
| 役割: `mwfLrWithArgmax`(定義的最大化)に対する floor_prod 実装版。 | |
| -/ | |
| def mwfLrWithArgmaxFloorProd | |
| (L R M A B C D : Int) | |
| (_hLR : L < R) (hM : 0 < M) (_hC0 : 0 ≤ C) (_hD0 : 0 ≤ D) : | |
| MwfLrArgResult := | |
| let nI := R - L | |
| let mI := M | |
| let qC := zfloorDiv C M hM | |
| let cI := zfloorMod C M hM | |
| let kI := C * L + D | |
| let qD := zfloorDiv kI M hM | |
| let dI := zfloorMod kI M hM | |
| let aI := A + B * qC | |
| let cst := A * L + B * qD | |
| let res : MwfElem := | |
| floorProd (Int.toNat nI) (Int.toNat mI) (Int.toNat cI) (Int.toNat dI) (mwfElemX aI) (mwfElemY B) | |
| match res.info? with | |
| | some info => | |
| { max := cst + info.best | |
| argmax := L + Int.ofNat info.arg } | |
| | none => | |
| -- `L<R` の下では本来起きないが、定義としては総称化しておく。 | |
| { max := cst | |
| argmax := L } | |
| /-- | |
| 目的: `floorProd` 版の区間最大値を返す。 | |
| 定義: `mwfLrWithArgmaxFloorProd` の `max` 射影。 | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `mwfLr` に対応する floor_prod 側 API。 | |
| -/ | |
| def mwfLrFloorProd | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) : Int := | |
| (mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0).max | |
| /-- | |
| 目的: `floorProd` 版の最小 `argmax` を返す。 | |
| 定義: `mwfLrWithArgmaxFloorProd` の `argmax` 射影。 | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `mwfLrArgmax` に対応する floor_prod 側 API。 | |
| -/ | |
| def mwfLrArgmaxFloorProd | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) : Int := | |
| (mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0).argmax | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 主張: floor_prod 版と定義版の構造体等式は、`max` と `argmax` の等式 2 本と同値。 | |
| 内容: 構造体の extensionality で分解・再構成する。 | |
| 証明: 射影 `congrArg` と `MwfLrArgResult` の ext を用いる。 | |
| 役割: `mwfLrWithArgmaxFloorProd = mwfLrWithArgmax` を成分ごとに還元する橋渡し定理。 | |
| -/ | |
| theorem mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) : | |
| mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrWithArgmax L R M A B C D hLR hM | |
| ↔ | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = mwfLr L R M A B C D hLR hM | |
| ∧ | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = mwfLrArgmax L R M A B C D hLR hM := by | |
| constructor | |
| · intro hEq | |
| constructor | |
| · have hMax := congrArg MwfLrArgResult.max hEq | |
| simpa only [mwfLrFloorProd, mwfLrWithArgmax] using hMax | |
| · have hArg := congrArg MwfLrArgResult.argmax hEq | |
| simpa only [mwfLrArgmaxFloorProd, mwfLrWithArgmax] using hArg | |
| · intro hField | |
| rcases hField with ⟨hMax, hArg⟩ | |
| cases hfp : mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 with | |
| | mk fpMax fpArg => | |
| cases hmwf : mwfLrWithArgmax L R M A B C D hLR hM with | |
| | mk mwfMax mwfArg => | |
| have hMwfMax : mwfLr L R M A B C D hLR hM = mwfMax := by | |
| simpa only [mwfLrWithArgmax] using congrArg MwfLrArgResult.max hmwf | |
| have hMwfArg : mwfLrArgmax L R M A B C D hLR hM = mwfArg := by | |
| simpa only [mwfLrWithArgmax] using congrArg MwfLrArgResult.argmax hmwf | |
| have hMax' : fpMax = mwfMax := by | |
| calc | |
| fpMax = mwfLr L R M A B C D hLR hM := by | |
| simpa only [mwfLrFloorProd, hfp] using hMax | |
| _ = mwfMax := hMwfMax | |
| have hArg' : fpArg = mwfArg := by | |
| calc | |
| fpArg = mwfLrArgmax L R M A B C D hLR hM := by | |
| simpa only [mwfLrArgmaxFloorProd, hfp] using hArg | |
| _ = mwfArg := hMwfArg | |
| cases hMax' | |
| cases hArg' | |
| rfl | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 主張: `max` と `argmax` の一致が示せれば、構造体レベルでも一致する。 | |
| 内容: `mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff` の `←` 方向。 | |
| 証明: 同値定理を `Iff.mpr` で適用。 | |
| 役割: 以後の正当化で使う組み立て用補題。 | |
| -/ | |
| theorem mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_of_fields | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) | |
| (hMax : | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLr L R M A B C D hLR hM) | |
| (hArg : | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrArgmax L R M A B C D hLR hM) : | |
| mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrWithArgmax L R M A B C D hLR hM := by | |
| exact (mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff | |
| L R M A B C D hLR hM hC0 hD0).2 ⟨hMax, hArg⟩ | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 主張: floor_prod 版の `max` と `argmax` がそれぞれ一致すれば、結果構造体も一致する。 | |
| 内容: `mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_of_fields` の別名。 | |
| 証明: 補題をそのまま適用する。 | |
| 役割: `mwfLrWithArgmaxFloorProd = mwfLrWithArgmax` の最終組み立て用インターフェース。 | |
| -/ | |
| theorem mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) | |
| (hMax : | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLr L R M A B C D hLR hM) | |
| (hArg : | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrArgmax L R M A B C D hLR hM) : | |
| mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrWithArgmax L R M A B C D hLR hM := by | |
| exact mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_of_fields | |
| L R M A B C D hLR hM hC0 hD0 hMax hArg | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 主張: 構造体等式が成り立てば `max` 成分も一致する。 | |
| 内容: 同値定理の `→` 方向から第1成分を取り出す。 | |
| 証明: `mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff` を展開。 | |
| 役割: `mwfLrFloorProd` 正当化の射影補題。 | |
| -/ | |
| theorem mwfLrFloorProd_eq_mwfLr_of_withArgmaxEq | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) | |
| (hEq : | |
| mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrWithArgmax L R M A B C D hLR hM) : | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLr L R M A B C D hLR hM := by | |
| exact (mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff | |
| L R M A B C D hLR hM hC0 hD0).1 hEq |>.1 | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 主張: 構造体等式が成り立てば `argmax` 成分も一致する。 | |
| 内容: 同値定理の `→` 方向から第2成分を取り出す。 | |
| 証明: `mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff` を展開。 | |
| 役割: `mwfLrArgmaxFloorProd` 正当化の射影補題。 | |
| -/ | |
| theorem mwfLrArgmaxFloorProd_eq_mwfLrArgmax_of_withArgmaxEq | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) | |
| (hEq : | |
| mwfLrWithArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrWithArgmax L R M A B C D hLR hM) : | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrArgmax L R M A B C D hLR hM := by | |
| exact (mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax_iff | |
| L R M A B C D hLR hM hC0 hD0).1 hEq |>.2 | |
| end FloorProd | |
| end MWF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment