Last active
March 11, 2026 09:02
-
-
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 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 < Δ` の判定変形・存在条件・最小解探索の基準になる中心定義。 | |
| -/ | |
| private 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 形を簡潔に書くために使う。 | |
| -/ | |
| private 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` の存在判定と探索上界の分岐軸になる。 | |
| -/ | |
| private 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 < Δ` の出発点。 | |
| -/ | |
| private 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)` 型の一次式判定へ落とす第一段。 | |
| -/ | |
| private 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 判定式への変換を担う。 | |
| -/ | |
| private 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` で連結する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 可解性証明・上界証明・探索判定の共通インターフェース。 | |
| -/ | |
| private 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} | |
| namespace Search | |
| namespace Internal | |
| /-- | |
| 目的: `x` 側での最小解仕様を述語として定義する。 | |
| 定義: `x0 ≥ 0`、`K < Δ(x0)`、および任意の可解 `y` に対する `x0 ≤ y` を束ねる。 | |
| 入力/前提: D A B K : Int、hD : 0 < D、hA : 0 < A。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 最小解が `D` の倍数であること(`dvd_of_IsLeastX`)を形式化する土台。 | |
| -/ | |
| private 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` の倍数境界に限られることを与える。 | |
| -/ | |
| private 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`)へ落とす正当化。 | |
| -/ | |
| private 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` の値を返す。 | |
| 役割: 最小解存在条件・二分探索仕様の共通前提。 | |
| -/ | |
| private 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`・存在条件・二分探索仕様の共通前提。 | |
| -/ | |
| private 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 | |
| end Internal | |
| end Search | |
| /-- | |
| 目的: 可解集合から `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, Search.Internal.SolX D A B K hD hA hB x) : Int := | |
| by | |
| classical | |
| exact sInf {x : Int | Search.Internal.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, Search.Internal.SolU D A B K hD hA hB u) : Int := | |
| by | |
| classical | |
| exact sInf {u : Int | Search.Internal.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, Search.Internal.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, Search.Internal.SolU D A B K hD hA hB u then | |
| uMinOf D A B K hD hA hB hex | |
| else | |
| -1 | |
| namespace Correctness | |
| namespace Internal | |
| /-- | |
| 入力/前提: 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` 側へ戻す橋渡し。 | |
| -/ | |
| private lemma xMin_eq_D_mul_uMinOf | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : ∃ u : Int, Search.Internal.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, Search.Internal.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 | Search.Internal.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 | Search.Internal.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 : Search.Internal.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 : Search.Internal.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 Search.Internal.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 : Search.Internal.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 : Search.Internal.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 : Search.Internal.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` による矛盾導出で示す。 | |
| 役割: 非可解ケースの返り値仕様を確定する。 | |
| -/ | |
| private lemma xMin_eq_neg_one_of_no_solution | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hno : ¬ ∃ u : Int, Search.Internal.SolU D A B K hD hA hB u) : | |
| xMin D A B K hD hA hB = -1 := by | |
| classical | |
| have hnoX : ¬ ∃ x : Int, Search.Internal.SolX D A B K hD hA hB x := by | |
| intro hexX | |
| have hBddX : BddBelow ({x : Int | Search.Internal.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 : Search.Internal.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 : Search.Internal.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 Search.Internal.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 : Search.Internal.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 Internal | |
| end Correctness | |
| 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` で反復利用する。 | |
| -/ | |
| private 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` の値を返す。 | |
| 役割: 存在定理・上界定理・二分探索正当化の共通仮定を簡潔にする。 | |
| -/ | |
| private def HasUSolution | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) : Prop := | |
| ∃ u : Int, Search.Internal.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` を明示せず使える形を与える。 | |
| -/ | |
| private 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) | |
| namespace Bounds | |
| namespace Internal | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hu0 : 0 ≤ u`, `hK : 0 ≤ K`。 | |
| 主張: 標準形 `A*B*K < ((D*u)%A)*Mof + Rof*u` が成り立てば `u` は `SolU` である。 | |
| 内容: `lt_Delta_iff_ABK_lt_canonical` の逆向きから `K < Delta(D*u)` を回収する。 | |
| 証明: `hu0` を `SolU` の第1成分に使い、第2成分は既存同値補題で与える。 | |
| 役割: `ExistAndBounds` 節で繰り返す `SolU` 構成の末尾を共通化する。 | |
| -/ | |
| private lemma solU_of_lt_canonical | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| {K u : Int} | |
| (hu0 : 0 ≤ u) | |
| (hK : 0 ≤ K) | |
| (hABK_lt_rhs : | |
| A * B * K < ((D * u) % A) * Mof D A B + Rof D A B * u) : | |
| Search.Internal.SolU D A B K hD hA hB u := by | |
| exact | |
| ⟨hu0, | |
| (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⟩ | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`。 | |
| 主張: `Mof D A B` は非負である。 | |
| 内容: `Mof = (A*B)/D` に展開し、正数どうしの除算の非負性を使う。 | |
| 証明: `Int.ediv_nonneg` を適用する。 | |
| 役割: `ExistAndBounds` 節で現れる非負項評価を短くする。 | |
| -/ | |
| private lemma Mof_nonneg | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) : | |
| 0 ≤ Mof D A B := by | |
| unfold Mof | |
| exact Int.ediv_nonneg (le_of_lt (Int.mul_pos hA hB)) (le_of_lt hD) | |
| /-- | |
| 入力/前提: 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` での必要条件導出と上界評価の鍵となる剰余評価。 | |
| -/ | |
| private 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` なら `u < (A*B*K)/R + 2` を満たす可解 `u` が存在する。 | |
| 内容: 候補 `u0 = (A*B*K)/R + 1` を取り、`R*u0 > A*B*K` と非負項で canonical 不等式を示す。 | |
| 証明: 除算不等式と `solU_of_lt_canonical` を連結する。 | |
| 役割: `R ≠ 0` ケースの存在性と上界証明で共有する witness を与える。 | |
| -/ | |
| private lemma exists_solU_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) : | |
| ∃ u : Int, Search.Internal.SolU D A B K hD hA hB u ∧ | |
| u < (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 := | |
| Mof_nonneg (D := D) (A := A) (B := B) hD hA hB | |
| 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 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 (le_add_of_nonneg_left hterm0) | |
| have huSol : Search.Internal.SolU D A B K hD hA hB u0 := | |
| solU_of_lt_canonical | |
| (D := D) (A := A) (B := B) | |
| hD hA hB hu0 hK hABK_lt_rhs | |
| have hu0_lt : u0 < (A * B * K) / (Rof D A B) + 2 := by | |
| dsimp only [u0] | |
| omega | |
| exact ⟨u0, huSol, hu0_lt⟩ | |
| /-- | |
| 入力/前提: `hR0 : Rof D A B = 0`。 | |
| 主張: `D * Mof D A B = A * B`。 | |
| 内容: 商剰余分解で余り項を消し、`Mof = (A*B)/D` を元の積へ戻す。 | |
| 証明: `Int.mul_ediv_add_emod` を `hR0` で簡約する。 | |
| 役割: `R = 0` 枝で `Mof` を含む積の式変形を共通化する。 | |
| -/ | |
| private lemma DMof_eq_AB_of_R_eq_zero | |
| (hR0 : Rof D A B = 0) : | |
| D * Mof D A B = A * B := by | |
| have hdvd : D ∣ A * B := by | |
| exact (Int.dvd_iff_emod_eq_zero).2 (by simpa only [Rof] using hR0) | |
| simpa only [Mof, mul_comm] using (Int.ediv_mul_cancel hdvd) | |
| /-- | |
| 入力/前提: hD : `0 < D`、hA : `0 < A`、hB : `0 < B`、hR0 : `Rof D A B = 0`。 | |
| 主張: `Mof D A B` は正である。 | |
| 内容: `D * Mof = A * B` と `A * B > 0` から `Mof > 0` を得る。 | |
| 証明: 積の正値を `Int.pos_of_mul_pos_left` に渡す。 | |
| 役割: `R = 0` 枝の可解候補構成と上界評価で再利用する。 | |
| -/ | |
| private lemma Mof_pos_of_R_eq_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hR0 : Rof D A B = 0) : | |
| 0 < Mof D A B := by | |
| have hABpos : 0 < A * B := Int.mul_pos hA hB | |
| have hprod : 0 < D * Mof D A B := by | |
| simpa only [DMof_eq_AB_of_R_eq_zero (D := D) (A := A) (B := B) hR0] 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 | |
| /-- | |
| 入力/前提: `hA : 0 < A`、`hglt : gcdDA D A < A`。 | |
| 主張: `0 < D % A`。 | |
| 内容: `gcd(D,A) < A` なら `A ∤ D` であり、剰余は 0 ではなく非負なので正である。 | |
| 証明: `Int.gcd_eq_right` と `Int.dvd_iff_emod_eq_zero` を使う。 | |
| 役割: `one_sol_of_R_eq_zero_of_K_zero` の局所算術を切り出す。 | |
| -/ | |
| private lemma Dmod_pos_of_gcd_lt_A | |
| (hA : 0 < A) | |
| (hglt : gcdDA D A < A) : | |
| 0 < D % A := by | |
| have hDmod0 : 0 ≤ D % A := Int.emod_nonneg _ (ne_of_gt hA) | |
| have hDmodNe : D % A ≠ 0 := by | |
| intro hmod | |
| have hgEq : gcdDA D A = A := by | |
| simpa only [gcdDA] using | |
| (Int.gcd_eq_right (le_of_lt hA) ((Int.dvd_iff_emod_eq_zero).2 hmod)) | |
| omega | |
| exact lt_of_le_of_ne hDmod0 hDmodNe.symm | |
| /-- | |
| 入力/前提: hD : `0 < D`、hA : `0 < A`、hB : `0 < B`、hK : `0 ≤ K`、 | |
| `hR0 : Rof D A B = 0`、`hK0 : K = 0`、`hcond : D*K + gcd(D,A) < A`。 | |
| 主張: `u = 1` は `SolU` の具体例である。 | |
| 内容: `gcd(D,A) < A` から `A ∤ D`、したがって `D % A > 0` を得て、 | |
| `K = 0` のとき `Δ` の右辺が正であることを示す。 | |
| 証明: `Mof > 0` と `D % A > 0` から右辺正値を作り canonical 判定へ戻す。 | |
| 役割: `uMin_lt_ABK_plus_two` の `R = 0, K = 0` 枝を短くする。 | |
| -/ | |
| private lemma one_sol_of_R_eq_zero_of_K_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) | |
| (hK0 : K = 0) | |
| (hcond : D * K + gcdDA D A < A) : | |
| Search.Internal.SolU D A B K hD hA hB 1 := by | |
| have hglt : gcdDA D A < A := by | |
| simpa only [hK0, mul_zero, zero_add] using hcond | |
| have hDmodPos : 0 < D % A := Dmod_pos_of_gcd_lt_A (D := D) (A := A) hA hglt | |
| have hMpos : 0 < Mof D A B := | |
| Mof_pos_of_R_eq_zero (D := D) (A := A) (B := B) hD hA hB hR0 | |
| have hABK_lt_rhs : | |
| A * B * K < | |
| ((D * (1 : Int)) % A) * Mof D A B + Rof D A B * (1 : Int) := by | |
| simpa only [hK0, hR0, mul_zero, mul_one, add_zero] using | |
| (show 0 < (D % A) * Mof D A B from Int.mul_pos hDmodPos hMpos) | |
| exact | |
| solU_of_lt_canonical | |
| (D := D) (A := A) (B := B) | |
| hD hA hB (by decide) hK hABK_lt_rhs | |
| /-- | |
| 入力/前提: `hA : 0 < A`。 | |
| 主張: `0 ≤ u < A / gcd(D,A)` かつ `(D*u) % A = A - gcd(D,A)` を満たす `u` が存在する。 | |
| 内容: `D = g*D1`, `A = g*A1` に既約化し、Bézout 係数から `D1*u ≡ -1 mod A1` を作る。 | |
| 証明: `u := (-gcdA D1 A1) % A1` を取り、合同式と剰余計算で示す。 | |
| 役割: `R = 0` ケースの具体的 witness 構成を共通化する。 | |
| -/ | |
| private lemma exists_u_lt_A_div_g_with_Du_mod_eq_A_sub_g | |
| (hA : 0 < A) : | |
| ∃ u : Int, | |
| 0 ≤ u ∧ | |
| u < A / gcdDA D A ∧ | |
| (D * u) % A = 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, Int.zero_emod, | |
| sub_zero] using (Int.negSucc_emod 0 hA1pos) | |
| 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) := by | |
| exact Int.mul_emod_mul_of_pos (a := g) (b := D1 * u) (c := A1) hg0 | |
| _ = g * (A1 - 1) := by rw [hremA1, hneg1] | |
| _ = A - g := by | |
| calc | |
| g * (A1 - 1) = g * A1 - g := by ring | |
| _ = A - g := by rw [hAsplit] | |
| refine ⟨u, hu0, ?_, ?_⟩ | |
| · simpa only [g, A1] | |
| · simpa only [g] using hrem | |
| /-- | |
| 入力/前提: 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` ケースの十分条件と具体的候補を与える中心補題。 | |
| -/ | |
| private 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, Search.Internal.SolU D A B K hD hA hB u ∧ u < A / gcdDA D A := by | |
| rcases exists_u_lt_A_div_g_with_Du_mod_eq_A_sub_g (D := D) (A := A) hA with | |
| ⟨u, hu0, huLt, hrem⟩ | |
| let g : Int := gcdDA D A | |
| have hABeqDM : A * B = D * Mof D A B := by | |
| simpa only using | |
| (DMof_eq_AB_of_R_eq_zero (D := D) (A := A) (B := B) hR0).symm | |
| have hMpos : 0 < Mof D A B := | |
| Mof_pos_of_R_eq_zero (D := D) (A := A) (B := B) hD hA hB hR0 | |
| 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 huSol : Search.Internal.SolU D A B K hD hA hB u := | |
| solU_of_lt_canonical | |
| (D := D) (A := A) (B := B) | |
| hD hA hB hu0 hK hABK_lt_rhs | |
| exact ⟨u, huSol, huLt⟩ | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`, | |
| `hR0 : Rof D A B = 0`, `huSol : SolU ... u`。 | |
| 主張: 必要条件 `D*K + gcd(D,A) < A` が成り立つ。 | |
| 内容: canonical 不等式と `((D*u)%A) ≤ A-g` を連結して右辺を `(A-g)*Mof` で押さえる。 | |
| 証明: `lt_Delta_iff_ABK_lt_canonical` と `Du_mod_A_bounds_with_gcd` を使う。 | |
| 役割: `R = 0` の存在条件の順方向を短い補題に分離する。 | |
| -/ | |
| private lemma DK_add_g_lt_A_of_solU_of_R_eq_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) | |
| {u : Int} | |
| (huSol : Search.Internal.SolU D A B K hD hA hB u) : | |
| D * K + gcdDA D A < A := by | |
| let g : Int := gcdDA D A | |
| have hABeqDM : A * B = D * Mof D A B := by | |
| simpa only using | |
| (DMof_eq_AB_of_R_eq_zero (D := D) (A := A) (B := B) hR0).symm | |
| have hMpos : 0 < Mof D A B := | |
| Mof_pos_of_R_eq_zero (D := D) (A := A) (B := B) hD hA hB hR0 | |
| rcases huSol with ⟨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 := | |
| (Du_mod_A_bounds_with_gcd (D := D) (A := A) (u := u) hA hu0).2 | |
| have hremM_le : ((D * u) % A) * Mof D A B ≤ (A - g) * Mof D A B := | |
| mul_le_mul_of_nonneg_right hrem_le (le_of_lt hMpos) | |
| 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 | |
| _ < ((D * u) % A) * Mof D A B := hABK_lt_remM | |
| _ ≤ (A - g) * Mof D A B := hremM_le | |
| 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, g] using this | |
| /-- | |
| 入力/前提: 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 で同値として確定する。 | |
| -/ | |
| private 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 | |
| constructor | |
| · intro hsol | |
| rcases hsol with ⟨u, huSol⟩ | |
| exact | |
| DK_add_g_lt_A_of_solU_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 huSol | |
| · 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`, `hK : 0 ≤ K`, | |
| `hex : HasUSolution ...`, `hR0 : Rof D A B = 0`。 | |
| 主張: `D*K + gcd(D,A) < A`。 | |
| 内容: `R = 0` での可解性同値の前向き射影。 | |
| 証明: `exists_u_iff_DK_add_g_lt_A_of_R_eq_zero` を適用する。 | |
| 役割: `ExistAndBounds` 節で繰り返す `hcond` の導出を共通化する。 | |
| -/ | |
| private lemma DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| (hR0 : Rof D A B = 0) : | |
| D * K + gcdDA D A < A := by | |
| simpa using | |
| (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).mp hex | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hu : 0 ≤ u`。 | |
| 主張: `Delta(D*u) ≤ u`。 | |
| 内容: `Delta_Du_rewrite` で `u - (...)` の形に戻し、補正項の非負性で押さえる。 | |
| 証明: `Mof_nonneg` と除算の非負性を組み合わせる。 | |
| 役割: `uMin_lower_bound` の算術部分を切り出す。 | |
| -/ | |
| private lemma Delta_Du_le_u | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| {u : Int} | |
| (hu : 0 ≤ u) : | |
| Delta D A B (D * u) hD hA hB ≤ u := by | |
| have hM0 : 0 ≤ Mof D A B := | |
| Mof_nonneg (D := D) (A := A) (B := B) hD hA hB | |
| have hDu0 : 0 ≤ D * u := mul_nonneg (le_of_lt hD) hu | |
| have hDiv0 : 0 ≤ (D * u) / A := Int.ediv_nonneg hDu0 (le_of_lt hA) | |
| have hSub0 : 0 ≤ ((Mof D A B * ((D * u) / A)) / B) := by | |
| exact Int.ediv_nonneg (mul_nonneg hM0 hDiv0) (le_of_lt hB) | |
| calc | |
| Delta D A B (D * u) hD hA hB = | |
| u - ((Mof D A B * ((D * u) / A)) / B) := by | |
| simpa only [Mof] using | |
| (Delta_Du_rewrite (D := D) (A := A) (B := B) (u := u) | |
| (M := Mof D A B) hD hA hB hu rfl) | |
| _ ≤ u := sub_le_self _ hSub0 | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 解があるなら `uMinOf ≥ K + 1`。 | |
| 内容: 任意可解 `b` について `Δ(D,A,B,D*b) ≤ b` から `K < b` を導き `K+1 ≤ b` を得る。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 探索区間の下界と最小解の基本的性質を与える。 | |
| -/ | |
| private 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 hDelta_le : Delta D A B (D * b) hD hA hB ≤ b := | |
| Delta_Du_le_u (D := D) (A := A) (B := B) hD hA hB hb0 | |
| have hKltb : K < b := lt_of_lt_of_le hbK hDelta_le | |
| exact (Int.add_one_le_iff).2 hKltb | |
| /-- | |
| 入力/前提: `hex : HasUSolution ...`、`huSol : SolU ... u`、`huLt : u < bound`。 | |
| 主張: 最小解 `uMinOf` も `bound` 未満である。 | |
| 内容: `csInf_le` で `uMinOf ≤ u` を取り出し、`u < bound` と連結する。 | |
| 証明: 可解集合の下方有界性と `sInf` の最小性で示す。 | |
| 役割: `uMin_lt_ABK_plus_two` などで繰り返す | |
| `sInf ≤ witness < bound` を共通化する。 | |
| -/ | |
| private lemma uMinOf_lt_of_sol_lt | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| {u bound : Int} | |
| (huSol : Search.Internal.SolU D A B K hD hA hB u) | |
| (huLt : u < bound) : | |
| uMinOf D A B K hD hA hB hex < bound := by | |
| have hBdd : BddBelow ({z : Int | Search.Internal.SolU D A B K hD hA hB z} : Set Int) := | |
| ⟨0, fun _ hz => hz.1⟩ | |
| unfold uMinOf | |
| exact lt_of_le_of_lt (csInf_le hBdd huSol) huLt | |
| /-- | |
| 入力/前提: `hex : HasUSolution ...`、`hExist : ∃ u, SolU ... u ∧ u < bound`。 | |
| 主張: `uMinOf < bound`。 | |
| 内容: witness を 1 つ取り出して `uMinOf_lt_of_sol_lt` に渡す。 | |
| 証明: 存在 witness を分解して既存補題を適用する。 | |
| 役割: `ExistAndBounds` 節の上界補題から `rcases` の重複を取り除く。 | |
| -/ | |
| private lemma uMinOf_lt_of_exists_sol_lt | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| {bound : Int} | |
| (hExist : | |
| ∃ u : Int, Search.Internal.SolU D A B K hD hA hB u ∧ u < bound) : | |
| uMinOf D A B K hD hA hB hex < bound := by | |
| rcases hExist with ⟨u, huSol, huLt⟩ | |
| simpa using | |
| uMinOf_lt_of_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex huSol huLt | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`。 | |
| 主張: `((A*B*K)/Rof) + 2 ≤ A*B*K + 2`。 | |
| 内容: 非負な分子に対して `⌊n/R⌋ ≤ n` を使う。 | |
| 証明: `Int.ediv_le_self` を `A*B*K` に適用する。 | |
| 役割: `uMin_lt_ABK_plus_two` の `R ≠ 0` 枝の算術を薄くする。 | |
| -/ | |
| private lemma floor_ABK_div_R_plus_two_le_ABK_plus_two | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hK : 0 ≤ K) : | |
| (A * B * K) / (Rof D A B) + 2 ≤ A * B * K + 2 := by | |
| 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 | |
| simpa only [add_le_add_iff_right] using add_le_add_left hdivLe 2 | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 可解なら常に粗い共通上界 `uMinOf < A*B*K + 2`。 | |
| 内容: `R = 0` / `R ≠ 0`(さらに `K = 0` / `K > 0`)で分岐し既存の鋭い上界を統合する。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 場合分け不要で使える初期探索上界を提供する。 | |
| -/ | |
| private 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 := | |
| DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0 | |
| by_cases hK0 : K = 0 | |
| · have hOneSol : Search.Internal.SolU D A B K hD hA hB 1 := | |
| one_sol_of_R_eq_zero_of_K_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hK0 hcond | |
| simpa only [hK0, mul_zero, zero_add, gt_iff_lt] using | |
| (uMinOf_lt_of_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex hOneSol (by decide)) | |
| · have hKpos : 0 < K := lt_of_le_of_ne hK (Ne.symm hK0) | |
| have hltAdiv : | |
| uMinOf D A B K hD hA hB hex < A / gcdDA D A := by | |
| have hcond : D * K + gcdDA D A < A := | |
| DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0 | |
| simpa using | |
| uMinOf_lt_of_exists_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| (exists_solU_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond) | |
| have hAdiv_le_A : A / gcdDA D A ≤ A := | |
| Int.ediv_le_self (gcdDA D A) (le_of_lt hA) | |
| have hBge1 : (1 : Int) ≤ B := (Int.lt_iff_add_one_le).1 hB | |
| have hKge1 : (1 : Int) ≤ K := (Int.lt_iff_add_one_le).1 hKpos | |
| have hB0 : 0 ≤ B := le_of_lt hB | |
| have hBKge1 : (1 : Int) ≤ B * K := by | |
| calc | |
| (1 : Int) = 1 * 1 := by ring | |
| _ ≤ B * 1 := by | |
| simpa only [one_mul, mul_one] using | |
| mul_le_mul_of_nonneg_right hBge1 (show 0 ≤ (1 : Int) by decide) | |
| _ ≤ B * K := by | |
| simpa only [one_mul] using mul_le_mul_of_nonneg_left hKge1 hB0 | |
| have hA_le_ABK : A ≤ A * B * K := by | |
| calc | |
| A = A * 1 := by ring | |
| _ ≤ A * (B * K) := by | |
| exact mul_le_mul_of_nonneg_left hBKge1 (le_of_lt hA) | |
| _ = A * B * K := by ring | |
| have hAdiv_le_ABK : A / gcdDA D A ≤ A * B * K := | |
| le_trans hAdiv_le_A hA_le_ABK | |
| omega | |
| · have hlt : uMinOf D A B K hD hA hB hex < (A * B * K) / (Rof D A B) + 2 := by | |
| simpa using | |
| uMinOf_lt_of_exists_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| (exists_solU_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0) | |
| exact | |
| lt_of_lt_of_le hlt | |
| (floor_ABK_div_R_plus_two_le_ABK_plus_two | |
| (D := D) (A := A) (B := B) (K := K) hA hB hK) | |
| end Internal | |
| end Bounds | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: 可解性条件と最小解上界を一括で与える総合定理。 | |
| 内容: `R ≠ 0` の存在性、`R = 0` の同値条件、および `uMinOf` の各種上界を同時に返す。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 本文 `lem:exist` に対応する統合インターフェース。 | |
| -/ | |
| private 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 | |
| refine ⟨?_, ?_, ?_⟩ | |
| · intro hRnz | |
| rcases Bounds.Internal.exists_solU_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz with | |
| ⟨u, huSol, _⟩ | |
| exact ⟨u, huSol⟩ | |
| · intro hR0 | |
| simpa using | |
| Bounds.Internal.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 | |
| refine ⟨?_, ?_, ?_⟩ | |
| · intro hR0 | |
| have hcond : D * K + gcdDA D A < A := | |
| Bounds.Internal.DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0 | |
| simpa using | |
| Bounds.Internal.uMinOf_lt_of_exists_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| (Bounds.Internal.exists_solU_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond) | |
| · intro hRnz | |
| simpa using | |
| Bounds.Internal.uMinOf_lt_of_exists_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| (Bounds.Internal.exists_solU_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz) | |
| · simpa using | |
| Bounds.Internal.uMin_lt_ABK_plus_two | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex | |
| end ExistAndBounds | |
| section BinarySearchMinSketch | |
| variable {D A B K L R n N X u : Int} | |
| namespace NoHit | |
| namespace Internal | |
| /-- | |
| 目的: 二分探索で使う評価関数 `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)` に接続する。 | |
| -/ | |
| private 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` を二分探索不変量として扱うための述語版。 | |
| -/ | |
| private 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` と同値化して `Δ` 側判定と探索手続きをつなぐ。 | |
| -/ | |
| private 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同値。 | |
| -/ | |
| private 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` 版のどちらでも扱えるようにする。 | |
| -/ | |
| private 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 | |
| exact (hNoDelta u hLu huR) | |
| ((lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := u) | |
| hD hA hB (le_trans hL0 hLu) hK).2 (lt_of_not_ge hge)) | |
| · intro hNoBK u hLu huR hDelta | |
| exact not_lt_of_ge (hNoBK u hLu huR) | |
| ((lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := u) | |
| hD hA hB (le_trans hL0 hLu) hK).1 hDelta) | |
| /-- | |
| 入力/前提: hnN : n ≤ N、hNo : NoHitBK D A B K 0 N。 | |
| 主張: `NoHitBK ... 0 N` が成り立てば、右端を縮めた `NoHitBK ... 0 n` も成り立つ。 | |
| 内容: `u < n ≤ N` から `u < N` を得て元の仮定を適用する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 区間最大の単調性(prefix 安全性)を述語で使う補題。 | |
| -/ | |
| private 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 を貼り合わせる。 | |
| 証明: 場合分けで示す。 | |
| 役割: 二分探索で「前半が安全なら後半だけ判定すればよい」を形式化する。 | |
| -/ | |
| private 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 | |
| exact hAll u (le_trans hn0 hnu) 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 | |
| end Internal | |
| end NoHit | |
| namespace Search | |
| namespace Internal | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `uMinOf` は可解集合 `{u | SolU ... u}` に属する。 | |
| 内容: 可解集合の下方有界性と `Int.csInf_mem` を使って示す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `uMinOf` 自身を具体的な可解点として使うための基本補題。 | |
| -/ | |
| private lemma uMinOf_mem | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| Search.Internal.SolU D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := by | |
| have hBdd : BddBelow ({u : Int | Search.Internal.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` の最小性を不等式として使うための補助補題。 | |
| -/ | |
| private 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 : Search.Internal.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 | Search.Internal.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` の値を返す。 | |
| 役割: 二分探索が満たすべき仕様を数学的に固定する。 | |
| -/ | |
| private def NmaxSpec | |
| (D A B K : Int) | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (Nmax : Int) : Prop := | |
| 0 ≤ Nmax ∧ | |
| NoHit.Internal.NoHitDelta D A B K hD hA hB 0 Nmax ∧ | |
| ∀ N : Int, 0 ≤ N → NoHit.Internal.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` は不可解)から最大性を導く。 | |
| 証明: 反証法で示す。 | |
| 役割: 「最小可解点 = 最大安全長」を形式的に確立する中心定理。 | |
| -/ | |
| private 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 : Search.Internal.SolU D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := | |
| 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 | |
| exact | |
| (not_lt_of_ge | |
| (uMinOf_le_of_sol | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex ⟨hu0, huDelta⟩)) | |
| huLt | |
| · intro N hN0 hNoHit | |
| by_contra hNle | |
| exact | |
| (hNoHit | |
| (uMinOf D A B K hD hA hB hex) | |
| huMin0 | |
| (lt_of_not_ge hNle)) | |
| huMinDelta | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `NmaxSpec` を満たす値は一意。 | |
| 内容: 2つの候補の最大性を相互適用して双方の `≤` を示し、反対称性で結ぶ。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 仕様を満たす探索結果が `uMinOf` と一致する根拠を与える。 | |
| -/ | |
| private 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` で戻す。 | |
| 証明: 式変形で示す。 | |
| 役割: 探索アルゴリズム仕様から最終解の正しさを得る接続定理。 | |
| -/ | |
| private 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 hEq : Nmax = uMinOf D A B K hD hA hB hex := | |
| NmaxSpec_unique | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hNmax | |
| (uMinOf_is_NmaxSpec (D := D) (A := A) (B := B) (K := K) hD hA hB hex) | |
| refine ⟨hEq.symm, ?_⟩ | |
| simpa [hEq] using | |
| (Correctness.Internal.xMin_eq_D_mul_uMinOf | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex) | |
| end Internal | |
| end Search | |
| namespace NoHit | |
| namespace Internal | |
| /-- | |
| 入力/前提: hA : 0 < A。 | |
| 主張: `fBinary` を平行移動した `Mwf.obj` 形に等式変換できる。 | |
| 内容: `u = (u-L)+L` で商の中身を再配置し、`fBinary = B*L + obj(..., u-L)` を示す。 | |
| 証明: 式変形で示す。 | |
| 役割: 区間最大 `F(L,R)` を `Mwf.mwf` 計算へ接続する前処理補題。 | |
| -/ | |
| private lemma fBinary_eq_shift_obj | |
| (hA : 0 < A) : | |
| fBinary D A B u = | |
| B * L + Mwf.Spec.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 [Mwf.Spec.obj, Mwf.Spec.zfloorDiv, neg_mul] | |
| ring | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`, `hNo : NoHitBK D A B K L R`。 | |
| 主張: shifted domain 上の任意の `x` に対し、対応する `Mwf.Spec.obj` は `B*K - B*L` 以下。 | |
| 内容: `u = L + x` と置いて `NoHitBK` を適用し、`fBinary_eq_shift_obj` で shifted `obj` に戻す。 | |
| 証明: `x ∈ dom(R-L)` から `L ≤ L+x < R` を作り、`fBinary` 側上界を差し引き形へ変換する。 | |
| 役割: `NoHitBK_iff_mwf_le` の `NoHitBK → mwf` 方向で、各点の上界評価を共通化する。 | |
| -/ | |
| private lemma shifted_obj_le_sub_of_NoHitBK | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hNo : NoHitBK D A B K L R) | |
| {x : Int} | |
| (hxDom : x ∈ Mwf.Spec.dom (R - L) (sub_pos.mpr hLR)) : | |
| Mwf.Spec.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K - B * L := by | |
| have hxI : x ∈ Finset.Icc (0 : Int) (R - L - 1) := by | |
| simpa only [Mwf.Spec.dom] using hxDom | |
| rcases Finset.mem_Icc.mp hxI with ⟨_hx0, hxN1⟩ | |
| have hxLt : x < R - L := by omega | |
| have hLu : L ≤ L + x := by omega | |
| have huR : L + x < R := by 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.Spec.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 [Mwf.Spec.obj, Mwf.Spec.zfloorDiv, neg_mul, hCancel] using hTmp | |
| have hSum : | |
| B * L + Mwf.Spec.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K := by | |
| simpa only [Mwf.Spec.obj, Mwf.Spec.zfloorDiv, neg_mul, hShift] using hfx | |
| exact | |
| (le_sub_iff_add_le).2 (by | |
| simpa only [Mwf.Spec.obj, Mwf.Spec.zfloorDiv, add_comm, neg_mul] using hSum) | |
| /-- | |
| 入力/前提: 有限集合 `s : Finset Int`、整数値関数 `f`、像の非空性 `hs`、 | |
| および各点評価 `f x ≤ z`。 | |
| 主張: `s.image f` の `max'` も `z` 以下。 | |
| 内容: `Finset.max'_le` と `Finset.mem_image` の定型処理を 1 本にまとめる。 | |
| 証明: 像の要素 `y` から逆像 `x ∈ s` を取り出し、点wise上界を適用する。 | |
| 役割: `mwf` / `mwfLr` の前向き上界化で重複する `max'` 評価を簡潔化する。 | |
| -/ | |
| private lemma max'_image_le_of_forall | |
| (s : Finset Int) | |
| (f : Int → Int) | |
| (hs : (s.image f).Nonempty) | |
| {z : Int} | |
| (h : ∀ x ∈ s, f x ≤ z) : | |
| (s.image f).max' hs ≤ z := by | |
| refine Finset.max'_le (s := s.image f) (H := hs) (x := z) ?_ | |
| intro y hy | |
| rcases Finset.mem_image.mp hy with ⟨x, hx, rfl⟩ | |
| exact h x hx | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`, `hNo : NoHitBK D A B K L R`。 | |
| 主張: shifted `mwf` 全体も `B*K - B*L` 以下、したがって `B*L + mwf ≤ B*K`。 | |
| 内容: `shifted_obj_le_sub_of_NoHitBK` を像全体へ持ち上げて `Finset.max'` を評価する。 | |
| 証明: `Mwf.Spec.img_nonempty` と `Finset.max'_le` を用いて最大値を押さえる。 | |
| 役割: `NoHitBK_iff_mwf_le` の前向き (`NoHitBK → mwf` 上界) を 1 本にまとめる。 | |
| -/ | |
| private lemma mwf_shift_le_of_NoHitBK | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hNo : 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 | |
| have hMwfLe : | |
| Mwf.mwf (R - L) A B (-(Mof D A B)) D (D * L) (sub_pos.mpr hLR) hA ≤ B * K - B * L := by | |
| simpa only [Mwf.Spec.img] using | |
| max'_image_le_of_forall | |
| (Mwf.Spec.dom (R - L) (sub_pos.mpr hLR)) | |
| (fun x => Mwf.Spec.obj B (-(Mof D A B)) D (D * L) A x hA) | |
| (Mwf.Spec.img_nonempty | |
| (N := R - L) (M := A) (A := B) (B := -(Mof D A B)) (C := D) (D := D * L) | |
| (sub_pos.mpr hLR) hA) | |
| (fun x hxDom => | |
| shifted_obj_le_sub_of_NoHitBK | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) | |
| hA hLR hNo hxDom) | |
| have hTmp : | |
| Mwf.mwf (R - L) A B (-(Mof D A B)) D (D * L) (sub_pos.mpr hLR) hA + B * L ≤ B * K := by | |
| exact (le_sub_iff_add_le).1 hMwfLe | |
| simpa only [add_comm] using hTmp | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`、shifted `mwf` 上界、 | |
| および `u ∈ [L,R)`。 | |
| 主張: `fBinary D A B u ≤ B * K`。 | |
| 内容: `x := u - L` を shifted domain に戻し、`obj ≤ mwf` と `fBinary_eq_shift_obj` | |
| を接続する。 | |
| 証明: `x ∈ dom(R-L)` を作って `Mwf.Spec.obj_le_mwf` を適用し、最後に `simpa` で戻す。 | |
| 役割: `NoHitBK_of_mwf_shift_le` の点wise評価部分を共通化する。 | |
| -/ | |
| private lemma fBinary_le_of_mwf_shift_le | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hMwf : | |
| B * L | |
| + Mwf.mwf (R - L) A B (-(Mof D A B)) D (D * L) (sub_pos.mpr hLR) hA | |
| ≤ B * K) | |
| {u : Int} | |
| (hLu : L ≤ u) | |
| (huR : u < R) : | |
| fBinary D A B u ≤ B * K := by | |
| let N0 : Int := R - L | |
| have hN0 : 0 < N0 := by | |
| exact sub_pos.mpr hLR | |
| have hMwfLe : | |
| Mwf.mwf N0 A B (-(Mof D A B)) D (D * L) hN0 hA ≤ B * K - B * L := by | |
| exact | |
| (le_sub_iff_add_le).2 (by | |
| simpa only [N0, add_comm] using hMwf) | |
| 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.Spec.dom N0 hN0 := by | |
| change x ∈ Finset.Icc (0 : Int) (N0 - 1) | |
| exact Finset.mem_Icc.mpr ⟨hx0, hxN1⟩ | |
| have hObj : | |
| Mwf.Spec.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K - B * L := by | |
| exact | |
| le_trans | |
| (Mwf.Spec.obj_le_mwf | |
| (N := N0) (M := A) (A := B) (B := -(Mof D A B)) (C := D) (D := D * L) (x := x) | |
| hN0 hA hxDom) | |
| hMwfLe | |
| have hShift : | |
| fBinary D A B u = | |
| B * L + Mwf.Spec.obj B (-(Mof D A B)) D (D * L) A x hA := by | |
| simpa only [x, Mwf.Spec.obj, Mwf.Spec.zfloorDiv, neg_mul] using | |
| (fBinary_eq_shift_obj (D := D) (A := A) (B := B) (L := L) (u := u) hA) | |
| have hTmp : | |
| Mwf.Spec.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 | |
| have hSum : | |
| B * L + Mwf.Spec.obj B (-(Mof D A B)) D (D * L) A x hA ≤ B * K := by | |
| simpa only [add_comm] using hTmp | |
| simpa only [hShift] using hSum | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`、および shifted `mwf` 上界。 | |
| 主張: `B * L + mwf ≤ B * K` なら区間 `[L,R)` は `NoHitBK`。 | |
| 内容: 任意の `u ∈ [L,R)` を `x = u - L` に戻し、`obj ≤ mwf` と `fBinary_eq_shift_obj` をつなぐ。 | |
| 証明: `x ∈ dom(R-L)` を作って `Mwf.Spec.obj_le_mwf` を適用し、最後に平行移動等式で戻す。 | |
| 役割: `NoHitBK_iff_mwf_le` の逆向き (`mwf` 上界 → NoHitBK`) を共通化する。 | |
| -/ | |
| private lemma NoHitBK_of_mwf_shift_le | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hMwf : | |
| B * L | |
| + Mwf.mwf (R - L) A B (-(Mof D A B)) D (D * L) (sub_pos.mpr hLR) hA | |
| ≤ B * K) : | |
| NoHitBK D A B K L R := by | |
| intro u hLu huR | |
| simpa using | |
| (fBinary_le_of_mwf_shift_le | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hLR hMwf hLu huR) | |
| /-- | |
| 入力/前提: 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回評価へ落とす実装接続の主補題。 | |
| -/ | |
| private 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 | |
| constructor | |
| · intro hNo | |
| simpa using | |
| (mwf_shift_le_of_NoHitBK | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hLR hNo) | |
| · intro hMwf | |
| simpa using | |
| (NoHitBK_of_mwf_shift_le | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hLR hMwf) | |
| /-- | |
| 入力/前提: `hA : 0 < A`。 | |
| 主張: 区間版 `mwfLr` で使う `Mwf.Spec.obj ... 0` は `fBinary` と一致する。 | |
| 内容: `0` 項を消して `B*u - M*((D*u)/A)` の形へ整える。 | |
| 証明: `Mwf.Spec.obj` を展開して環計算で示す。 | |
| 役割: `NoHitBK_iff_mwfLr_le` で `obj` と `fBinary` を毎回展開しないための補助。 | |
| -/ | |
| private lemma obj_eq_fBinary | |
| (hA : 0 < A) : | |
| Mwf.Spec.obj B (-(Mof D A B)) D 0 A u hA = fBinary D A B u := by | |
| calc | |
| Mwf.Spec.obj B (-(Mof D A B)) D 0 A u hA | |
| = B * u + (-(Mof D A B)) * ((D * u + 0) / A) := by | |
| simp only [Mwf.Spec.obj, Mwf.Spec.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] | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`、`mwfLr ... ≤ B*K`、 | |
| および `u ∈ [L,R)`。 | |
| 主張: `fBinary D A B u ≤ B * K`。 | |
| 内容: `u` を `domLr` の元として `Finset.le_max'` で `obj ≤ mwfLr` を得て、 | |
| `obj_eq_fBinary` で `fBinary` に戻す。 | |
| 証明: 区間所属を `domLr` 所属へ変換し、`le_trans` と `simpa` で示す。 | |
| 役割: `NoHitBK_of_mwfLr_le` の点wise評価部分を共通化する。 | |
| -/ | |
| private lemma fBinary_le_of_mwfLr_le | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hMwf : Mwf.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA ≤ B * K) | |
| {u : Int} | |
| (hLu : L ≤ u) | |
| (huR : u < R) : | |
| fBinary D A B u ≤ B * K := by | |
| have huR1 : u ≤ R - 1 := by omega | |
| have huDom : u ∈ Mwf.Spec.domLr L R hLR := by | |
| change u ∈ Finset.Icc L (R - 1) | |
| exact Finset.mem_Icc.mpr ⟨hLu, huR1⟩ | |
| have hObjLe : | |
| Mwf.Spec.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 | |
| exact | |
| Finset.le_max' (s := Mwf.Spec.imgLr L R A B (-(Mof D A B)) D 0 hLR hA) | |
| (x := Mwf.Spec.obj B (-(Mof D A B)) D 0 A u hA) | |
| (Finset.mem_image.mpr ⟨u, huDom, rfl⟩) | |
| simpa only [obj_eq_fBinary (D := D) (A := A) (B := B) (u := u) hA] using | |
| le_trans hObjLe hMwf | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`, `hNo : NoHitBK D A B K L R`。 | |
| 主張: 区間版最大値 `mwfLr` も `B*K` 以下。 | |
| 内容: 各 `u ∈ [L,R)` で `fBinary ≤ B*K` を使い、像の `max'` を上から抑える。 | |
| 証明: `Mwf.Spec.imgLr_nonempty` と `Finset.max'_le` を用いる。 | |
| 役割: `NoHitBK_iff_mwfLr_le` の前向き (`NoHitBK → mwfLr` 上界) を分離する。 | |
| -/ | |
| private lemma mwfLr_le_of_NoHitBK | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hNo : NoHitBK D A B K L R) : | |
| Mwf.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA ≤ B * K := by | |
| unfold Mwf.mwfLr | |
| simpa only [Mwf.Spec.imgLr] using | |
| max'_image_le_of_forall | |
| (Mwf.Spec.domLr L R hLR) | |
| (fun u => Mwf.Spec.obj B (-(Mof D A B)) D 0 A u hA) | |
| (Mwf.Spec.imgLr_nonempty | |
| (L := L) (R := R) (M := A) (A := B) (B := -(Mof D A B)) (C := D) (D := 0) hLR hA) | |
| (fun u huDom => by | |
| have huI : u ∈ Finset.Icc L (R - 1) := by | |
| simpa only [Mwf.Spec.domLr] using huDom | |
| rcases Finset.mem_Icc.mp huI with ⟨hLu, huR1⟩ | |
| have huR : u < R := by omega | |
| simpa only [obj_eq_fBinary (D := D) (A := A) (B := B) (u := u) hA] using | |
| hNo u hLu huR) | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hLR : L < R`、`Mwf.mwfLr ... ≤ B*K`。 | |
| 主張: 区間 `[L,R)` では `NoHitBK D A B K L R`。 | |
| 内容: 任意の `u ∈ [L,R)` を像の要素として `Finset.le_max'` に流し、`obj_eq_fBinary` で戻す。 | |
| 証明: `u ∈ domLr` の所属から `obj ≤ mwfLr` を得て、仮定と合成する。 | |
| 役割: `NoHitBK_iff_mwfLr_le` の逆向き (`mwfLr` 上界 → NoHitBK`) を分離する。 | |
| -/ | |
| private lemma NoHitBK_of_mwfLr_le | |
| (hA : 0 < A) | |
| (hLR : L < R) | |
| (hMwf : Mwf.mwfLr L R A B (-(Mof D A B)) D 0 hLR hA ≤ B * K) : | |
| NoHitBK D A B K L R := by | |
| intro u hLu huR | |
| exact | |
| fBinary_le_of_mwfLr_le | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hLR hMwf hLu huR | |
| /-- | |
| 入力/前提: 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` に接続するために使う。 | |
| -/ | |
| private 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 | |
| exact mwfLr_le_of_NoHitBK | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hLR hNo | |
| · intro hMwf | |
| exact NoHitBK_of_mwfLr_le | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hLR hMwf | |
| /-- | |
| 入力/前提: hD : 0 < D。 | |
| 主張: `D > 0` の下で `D*u < X ↔ u < (X + D - 1) / D`。 | |
| 内容: `u+1` 形に変換して `Int.le_ediv_iff_mul_le` を往復する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: `x` 側閾値比較を `u` 側の天井除算比較へ変換する。 | |
| -/ | |
| private 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 | |
| end Internal | |
| end NoHit | |
| namespace NoHit | |
| namespace Internal | |
| /-- | |
| 入力/前提: hD : 0 < D、hA : 0 < A、hB : 0 < B。 | |
| 主張: `¬ NoHitDelta ... L R` は区間内のヒット点存在と同値。 | |
| 内容: `NoHitDelta` の全称否定を `simp` で存在形へ展開する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 不成立判定を具体的な証人 `u` の存在として扱う補助補題。 | |
| -/ | |
| private 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` 自身を証人に使う。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 区間判定と最小解の位置比較を同一視する。 | |
| -/ | |
| private 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 | |
| Divapprox.Search.Internal.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 | |
| Divapprox.Search.Internal.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、可解性 `hex`。 | |
| 主張: `xMin < X` は `uMinOf < (X + D - 1) / D` と同値。 | |
| 内容: `xMin = D * uMinOf` と `mul_lt_X_iff_lt_ceilDiv` を直接つなぐ。 | |
| 証明: `xMin_eq_D_mul_uMinOf` で左辺を `D*uMinOf` に変換し、ceiling 除算補題を適用する。 | |
| 役割: `xMin_lt_X_iff_not_NoHitDelta` から `xMin` と `uMinOf` の換算部分を切り出す。 | |
| -/ | |
| private lemma xMin_lt_X_iff_uMin_lt_ceilDiv | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| xMin D A B K hD hA hB < X ↔ | |
| uMinOf D A B K hD hA hB hex < (X + D - 1) / D := by | |
| have hxEq : | |
| xMin D A B K hD hA hB = D * uMinOf D A B K hD hA hB hex := by | |
| exact | |
| Correctness.Internal.xMin_eq_D_mul_uMinOf | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| simpa only [hxEq, gt_iff_lt] using | |
| (NoHit.Internal.mul_lt_X_iff_lt_ceilDiv | |
| (D := D) (X := X) (u := uMinOf D A B K hD hA hB hex) hD) | |
| /-- | |
| 入力/前提: 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回評価に帰着する判定定理。 | |
| -/ | |
| private 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] | |
| exact | |
| (xMin_lt_X_iff_uMin_lt_ceilDiv | |
| (D := D) (A := A) (B := B) (K := K) (X := X) hD hA hB hex).trans | |
| (not_NoHitDelta_zero_iff_uMin_lt | |
| (D := D) (A := A) (B := B) (K := K) (N := (X + D - 1) / D) hD hA hB hex).symm | |
| end Internal | |
| end NoHit | |
| end BinarySearchMinSketch | |
| section Executable | |
| /-- | |
| 目的: 区間最大値判定 `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` 側が安全か)に用いる。 | |
| -/ | |
| private 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.Impl.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` の反復本体。 | |
| -/ | |
| private 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` 探索インターフェース。 | |
| -/ | |
| private 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 | |
| namespace Impl | |
| /-- | |
| 目的: 問題 `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 Impl | |
| 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} | |
| namespace NoHit | |
| namespace Internal | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hL0 : 0 ≤ L`。 | |
| 主張: 判定 `mwfLr_iter_le` は `NoHitBK` と同値。 | |
| 内容: `L < R` の場合は `Mwf.mwfLr_iter_collect` と `NoHitBK_iff_mwfLr_le` に還元し、 | |
| `L ≥ R` の場合は空区間で自明。 | |
| 証明: 場合分けと `simp` で示す。 | |
| 役割: 実装側 Bool 判定を論理側述語へ持ち上げる接続補題。 | |
| -/ | |
| private 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.Impl.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.Correctness.mwfLr_iter_correct L R A B (-(Mof D A B)) D 0 hLR hA | |
| 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 [mwfLr_iter_le, hLR, hA, hCollect] | |
| exact hBool.trans | |
| (NoHitBK_iff_mwfLr_le | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hL0 hLR).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] | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hL0 : 0 ≤ L`、判定値が `true`。 | |
| 主張: 左区間 `[L,R)` は `NoHitBK` を満たす。 | |
| 内容: `mwfLr_iter_le_iff_NoHitBK` の前向き射影。 | |
| 証明: 同値補題の `mp`。 | |
| 役割: 二分探索本体で safe 分岐から論理的不変量を取り出す。 | |
| -/ | |
| private lemma NoHitBK_of_mwfLr_iter_le_true | |
| {L R : Int} | |
| (hA : 0 < A) (hL0 : 0 ≤ L) | |
| (hSafe : mwfLr_iter_le (B * K) L R A B (-(Mof D A B)) D 0 = true) : | |
| NoHitBK D A B K L R := | |
| (mwfLr_iter_le_iff_NoHitBK (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hL0).mp | |
| hSafe | |
| /-- | |
| 入力/前提: `hA : 0 < A`, `hL0 : 0 ≤ L`、判定値が `true` でない。 | |
| 主張: 左区間 `[L,R)` には unsafe 点 `u` が存在する。 | |
| 内容: `mwfLr_iter_le_iff_NoHitBK` で `¬ NoHitBK` に戻し、存在補題へ送る。 | |
| 証明: 反証法で `NoHitBK` を排し、`not_NoHitBK_iff_exists_hit` を適用する。 | |
| 役割: 二分探索本体で unsafe 分岐の証人抽出を 1 行にする。 | |
| -/ | |
| private lemma exists_hit_of_mwfLr_iter_le_ne_true | |
| {L R : Int} | |
| (hA : 0 < A) (hL0 : 0 ≤ L) | |
| (hUnsafe : mwfLr_iter_le (B * K) L R A B (-(Mof D A B)) D 0 ≠ true) : | |
| ∃ u : Int, L ≤ u ∧ u < R ∧ B * K < fBinary D A B u := by | |
| classical | |
| have hNo : ¬ NoHitBK D A B K L R := by | |
| intro hNoHit | |
| exact hUnsafe <| | |
| (mwfLr_iter_le_iff_NoHitBK | |
| (D := D) (A := A) (B := B) (K := K) (L := L) (R := R) hA hL0).mpr hNoHit | |
| simpa [NoHitBK, not_le] using hNo | |
| end Internal | |
| end NoHit | |
| /-- | |
| 入力/前提: なし(古典論理)。 | |
| 主張: `¬ NoHitBK ... L R` は区間内の unsafe 点の存在と同値。 | |
| 内容: 全称否定を存在形に展開する。 | |
| 証明: 反証法で示す。 | |
| 役割: 左半区間が unsafe な分岐で証人 `u` を取り出すために使う。 | |
| -/ | |
| private lemma not_NoHitBK_iff_exists_hit | |
| {L R : Int} : | |
| ¬ Divapprox.NoHit.Internal.NoHitBK D A B K L R ↔ | |
| ∃ u : Int, L ≤ u ∧ u < R ∧ | |
| B * K < Divapprox.NoHit.Internal.fBinary D A B u := by | |
| classical | |
| simp [Divapprox.NoHit.Internal.NoHitBK, not_le] | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、可解性 `hex`。 | |
| 主張: `uMinOf` 自身は `B*K < fBinary ...` を満たす unsafe 点である。 | |
| 内容: `uMinOf_mem` で得た `K < Delta` を `lt_Delta_iff_BK_lt_fBinary` で移す。 | |
| 証明: 2 本の既存補題の直接合成。 | |
| 役割: `compute_u_binary_eq_uMinOf_of_hi` で目標点の unsafe 性を 1 行で得る。 | |
| -/ | |
| private lemma uMinOf_unsafe_fBinary | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| B * K < | |
| Divapprox.NoHit.Internal.fBinary D A B | |
| (uMinOf D A B K hD hA hB hex) := by | |
| have huMin : Search.Internal.SolU D A B K hD hA hB (uMinOf D A B K hD hA hB hex) := | |
| Divapprox.Search.Internal.uMinOf_mem | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| simpa using | |
| (Divapprox.NoHit.Internal.lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) | |
| (u := uMinOf D A B K hD hA hB hex) hD hA hB huMin.1 hK).1 huMin.2 | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、可解性 `hex`、 | |
| `u` の非負性と unsafe 証明。 | |
| 主張: `uMinOf ... ≤ u`。 | |
| 内容: `B*K < fBinary ... u` を `K < Delta ...` に戻し、`uMinOf_le_of_sol` を適用する。 | |
| 証明: 既存の変換補題と最小性補題の合成。 | |
| 役割: `compute_u_binary_eq_uMinOf_of_hi` で最小性を 1 行で使う。 | |
| -/ | |
| private lemma uMinOf_le_of_unsafe_fBinary | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| {u : Int} | |
| (hu0 : 0 ≤ u) | |
| (huUnsafe : B * K < Divapprox.NoHit.Internal.fBinary D A B u) : | |
| uMinOf D A B K hD hA hB hex ≤ u := by | |
| simpa using | |
| Divapprox.Search.Internal.uMinOf_le_of_sol | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| ⟨hu0, | |
| (Divapprox.NoHit.Internal.lt_Delta_iff_BK_lt_fBinary | |
| (D := D) (A := A) (B := B) (K := K) (u := u) hD hA hB hu0 hK).2 huUnsafe⟩ | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、可解性 `hex`。 | |
| 主張: `tgt := uMinOf ...` は binary search target の 2 条件 | |
| 「unsafe」と「最小性」を満たす。 | |
| 内容: unsafe 性は `uMinOf_unsafe_fBinary`、最小性は | |
| `uMinOf_le_of_unsafe_fBinary` をそのまま束ねる。 | |
| 証明: 2 本の既存補題を組にして返す。 | |
| 役割: `compute_u_binary_eq_uMinOf_of_hi` の前提準備を 1 箇所にまとめる。 | |
| -/ | |
| private lemma uMinOf_binary_target_spec | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) : | |
| B * K < Divapprox.NoHit.Internal.fBinary D A B (uMinOf D A B K hD hA hB hex) ∧ | |
| (∀ u : Int, 0 ≤ u → | |
| B * K < Divapprox.NoHit.Internal.fBinary D A B u → | |
| uMinOf D A B K hD hA hB hex ≤ u) := by | |
| refine ⟨?_, ?_⟩ | |
| · simpa using | |
| (uMinOf_unsafe_fBinary | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex) | |
| · intro u hu0 huUnsafe | |
| simpa using | |
| (uMinOf_le_of_unsafe_fBinary | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hu0 huUnsafe) | |
| /-- | |
| 入力/前提: `lo ≤ hi`。 | |
| 主張: 幅 `hi - lo` は燃料候補 `Int.toNat (hi - lo + 1)` 以下。 | |
| 内容: `hi - lo + 1` の非負性で `Int.toNat` を外し、`n ≤ n+1` を使う。 | |
| 証明: `Int.toNat_of_nonneg` と算術。 | |
| 役割: `compute_u_binary_eq_uMinOf_of_hi` の初期 fuel 上界を共通化する。 | |
| -/ | |
| private lemma width_le_toNat_add_one (lo hi : Int) (hlohi : lo ≤ hi) : | |
| hi - lo ≤ (Int.toNat (hi - lo + 1) : Int) := by | |
| have hCast : (Int.toNat (hi - lo + 1) : Int) = hi - lo + 1 := by | |
| exact Int.toNat_of_nonneg (by omega) | |
| calc | |
| hi - lo ≤ hi - lo + 1 := by omega | |
| _ = (Int.toNat (hi - lo + 1) : Int) := by | |
| symm | |
| exact hCast | |
| /-- | |
| 入力/前提: `hA : 0 < A`、`0 ≤ lo ≤ tgt`、左半区間 `[lo, mid)` が safe。 | |
| 主張: `mid ≤ tgt`。 | |
| 内容: `tgt < mid` と仮定すると、safe 性から `tgt` 自身が safe になり | |
| `hTgtUnsafe` に矛盾する。 | |
| 証明: `NoHitBK_of_mwfLr_iter_le_true` を使って左半区間の `NoHitBK` を取り出し、 | |
| 反証法で示す。 | |
| 役割: `compute_u_binary_aux_eq_tgt` の safe 分岐から midpoint 比較だけを切り出す。 | |
| -/ | |
| private lemma mid_le_tgt_of_left_safe | |
| (hA : 0 < A) | |
| {lo mid tgt : Int} | |
| (hlo0 : 0 ≤ lo) | |
| (hloTgt : lo ≤ tgt) | |
| (hTgtUnsafe : B * K < Divapprox.NoHit.Internal.fBinary D A B tgt) | |
| (hSafe : mwfLr_iter_le (B * K) lo mid A B (-(Mof D A B)) D 0 = true) : | |
| mid ≤ tgt := by | |
| have hNoLeft : Divapprox.NoHit.Internal.NoHitBK D A B K lo mid := by | |
| simpa using | |
| (NoHit.Internal.NoHitBK_of_mwfLr_iter_le_true | |
| (D := D) (A := A) (B := B) (K := K) (L := lo) (R := mid) hA hlo0 hSafe) | |
| by_contra hNot | |
| exact | |
| (not_lt_of_ge (hNoLeft tgt hloTgt (lt_of_not_ge hNot))) hTgtUnsafe | |
| /-- | |
| 入力/前提: `hA : 0 < A`、`0 ≤ lo`、左半区間 `[lo, mid)` が unsafe、 | |
| `tgt` は最小 unsafe 点。 | |
| 主張: `tgt < mid`。 | |
| 内容: 左半区間内の unsafe witness `u` を取り出し、最小性 `tgt ≤ u` と `u < mid` | |
| をつなぐ。 | |
| 証明: `exists_hit_of_mwfLr_iter_le_ne_true` で witness を取得して示す。 | |
| 役割: `compute_u_binary_aux_eq_tgt` の unsafe 分岐から midpoint 比較だけを切り出す。 | |
| -/ | |
| private lemma tgt_lt_mid_of_left_unsafe | |
| (hA : 0 < A) | |
| {lo mid tgt : Int} | |
| (hlo0 : 0 ≤ lo) | |
| (hTgtMin : | |
| ∀ u : Int, 0 ≤ u → | |
| B * K < Divapprox.NoHit.Internal.fBinary D A B u → tgt ≤ u) | |
| (hUnsafe : mwfLr_iter_le (B * K) lo mid A B (-(Mof D A B)) D 0 ≠ true) : | |
| tgt < mid := by | |
| rcases | |
| NoHit.Internal.exists_hit_of_mwfLr_iter_le_ne_true | |
| (D := D) (A := A) (B := B) (K := K) (L := lo) (R := mid) hA hlo0 hUnsafe | |
| with ⟨u, hLu, huMid, huUnsafe⟩ | |
| exact lt_of_le_of_lt (hTgtMin u (le_trans hlo0 hLu) huUnsafe) huMid | |
| /-- | |
| 入力/前提: `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` の中核補題。 | |
| -/ | |
| private lemma compute_u_binary_aux_eq_tgt | |
| (hA : 0 < A) | |
| (tgt : Int) | |
| (hTgtUnsafe : B * K < Divapprox.NoHit.Internal.fBinary D A B tgt) | |
| (hTgtMin : | |
| ∀ u : Int, 0 ≤ u → | |
| B * K < Divapprox.NoHit.Internal.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 hMidLeTgt : mid ≤ tgt := | |
| mid_le_tgt_of_left_safe | |
| (D := D) (A := A) (B := B) (K := K) hA hlo0 hloTgt hTgtUnsafe hSafe | |
| 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 hTgtLtMid : tgt < mid := | |
| tgt_lt_mid_of_left_unsafe | |
| (D := D) (A := A) (B := B) (K := K) hA hlo0 hTgtMin hSafe | |
| 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] | |
| namespace Impl | |
| namespace Internal | |
| /-- | |
| 入力/前提: `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` の両分岐で使う共通接続補題。 | |
| -/ | |
| private 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 | |
| have hSpec := | |
| uMinOf_binary_target_spec (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex | |
| have hlo0 : 0 ≤ K + 1 := by omega | |
| have hWidth : | |
| hi - (K + 1) ≤ (Int.toNat (hi - (K + 1) + 1) : Int) := by | |
| exact width_le_toNat_add_one (K + 1) hi (le_trans hlo (le_of_lt htgtHi)) | |
| simpa only [compute_u_binary] using | |
| (compute_u_binary_aux_eq_tgt | |
| (D := D) (A := A) (B := B) (K := K) | |
| hA (uMinOf D A B K hD hA hB hex) hSpec.1 hSpec.2 | |
| (Int.toNat (hi - (K + 1) + 1)) (K + 1) hi | |
| hlo0 hlo htgtHi hWidth) | |
| end Internal | |
| end Impl | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、 | |
| 可解性 `hex` と上端 `hi` に対する `uMinOf < hi`。 | |
| 主張: 実装側 `compute_u_binary` は `uMinOf` を返し、したがって `D` 倍しても一致する。 | |
| 内容: 下界 `K + 1 ≤ uMinOf` は `uMin_lower_bound` で与え、上界仮定とともに | |
| `Impl.Internal.compute_u_binary_eq_uMinOf_of_hi` へ渡す。 | |
| 証明: 共通下界を作って `compute_u_binary_eq_uMinOf_of_hi` を適用し、最後に `simp` する。 | |
| 役割: `hbinR0` / `hbinRnz` の共通骨格をまとめる。 | |
| -/ | |
| private lemma D_mul_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) | |
| (htgtHi : uMinOf D A B K hD hA hB hex < hi) : | |
| D * compute_u_binary (B * K) (K + 1) hi A B (Mof D A B) D hA = | |
| D * uMinOf D A B K hD hA hB hex := by | |
| simpa using congrArg (fun u => D * u) | |
| (Impl.Internal.compute_u_binary_eq_uMinOf_of_hi | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hi | |
| (Bounds.Internal.uMin_lower_bound | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex) | |
| htgtHi) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、 | |
| 可解性 `hex`、`hR0 : Rof D A B = 0`。 | |
| 主張: `D * K + gcdDA D A < A`。 | |
| 内容: `R = 0` での可解性同値から必要条件を取り出す。 | |
| 証明: `Bounds.Internal.exists_u_iff_DK_add_g_lt_A_of_R_eq_zero` の前向き射影。 | |
| 役割: `hbinR0` と `compute_xMin_eq_D_mul_uMinOf_of_R_eq_zero` で | |
| `hiff.mp hex` の重複をなくす。 | |
| -/ | |
| private lemma DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| (hR0 : Rof D A B = 0) : | |
| D * K + gcdDA D A < A := by | |
| simpa using | |
| (Bounds.Internal.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).mp hex | |
| /-- | |
| 入力/前提: `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`。 | |
| 主張: `R = 0` の不可解条件から、`SolU` の witness は存在しない。 | |
| 内容: `R = 0` での可解性同値の contraposition を、 | |
| `HasUSolution` から `∃ u, SolU ... u` への変換までまとめる。 | |
| 証明: `exists_u_iff_DK_add_g_lt_A_of_R_eq_zero` の逆向きを `mt` し、`simpa` で整える。 | |
| 役割: `compute_xMin_eq_xMin_of_R_eq_zero` の不可解枝にある定型変換を共通化する。 | |
| -/ | |
| private lemma no_solU_of_not_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) | |
| (hcond : ¬ D * K + gcdDA D A < A) : | |
| ¬ ∃ u : Int, Search.Internal.SolU D A B K hD hA hB u := by | |
| have hnoU : ¬ HasUSolution D A B K hD hA hB := by | |
| exact mt | |
| ((Bounds.Internal.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).mp) | |
| hcond | |
| simpa only [not_exists, HasUSolution] using hnoU | |
| /-- | |
| 入力/前提: `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` と `A/g` 未満の witness 構成で探索範囲を閉じる。 | |
| 証明: `compute_u_binary_eq_uMinOf_of_hi` を `hi = A/g` に適用する。 | |
| 役割: `compute_xMin_eq_xMin` の `R=0` 可解分岐を閉じる。 | |
| -/ | |
| private 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 htgtHi : uMinOf D A B K hD hA hB hex < A / gcdDA D A := by | |
| have hcond : D * K + gcdDA D A < A := | |
| DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0 | |
| simpa using | |
| Bounds.Internal.uMinOf_lt_of_exists_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| (Bounds.Internal.exists_solU_lt_A_div_g_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond) | |
| simpa using | |
| D_mul_compute_u_binary_eq_uMinOf_of_hi | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex (A / gcdDA D A) htgtHi | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`。 | |
| 主張: `R≠0` かつ可解な場合、実装側 `compute_u_binary` が `uMinOf` と一致する(`x=D*u` 形)。 | |
| 内容: `uMin_lower_bound` と `floor(ABK/R)+2` 未満の witness 構成で探索範囲を閉じる。 | |
| 証明: `compute_u_binary_eq_uMinOf_of_hi` を `hi = floor(ABK/R)+2` に適用する。 | |
| 役割: `compute_xMin_eq_xMin` の `R≠0` 分岐を閉じる。 | |
| -/ | |
| private 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 | |
| have htgtHi : | |
| uMinOf D A B K hD hA hB hex < (A * B * K) / (Rof D A B) + 2 := by | |
| simpa using | |
| Bounds.Internal.uMinOf_lt_of_exists_sol_lt | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex | |
| (Bounds.Internal.exists_solU_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz) | |
| simpa only [Lean.Elab.WF.paramLet] using | |
| D_mul_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) htgtHi | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、 | |
| 可解性 `hex`、`hR0 : Rof D A B = 0`。 | |
| 主張: `R = 0` かつ可解な場合、実装側 `compute_xMin` は `D * uMinOf` を返す。 | |
| 内容: `R = 0` の可解条件を回収し、`hbinR0` に接続する。 | |
| 証明: `compute_xMin` の該当分岐を展開し、`hbinR0` を適用する。 | |
| 役割: `compute_xMin_eq_xMin` の `R = 0` 可解分岐を helper に分離する。 | |
| -/ | |
| private lemma compute_xMin_eq_D_mul_uMinOf_of_R_eq_zero | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| (hR0 : Rof D A B = 0) : | |
| Impl.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 | |
| (DK_add_g_lt_A_of_hasUSolution_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0) | |
| simpa only [Impl.compute_xMin, hD, ↓reduceDIte, hA, hB, hK, hR0, hnotle] using | |
| (hbinR0 (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、 | |
| `hR0 : Rof D A B = 0`、`hLe : A ≤ D * K + gcdDA D A`。 | |
| 主張: `R = 0` かつ不可解な枝では、実装側 `compute_xMin` は `-1` を返す。 | |
| 内容: `compute_xMin` の `R = 0`・`No=true` 分岐を読むだけである。 | |
| 証明: 定義展開と `simp` による。 | |
| 役割: `compute_xMin_eq_xMin` の `R = 0` 不可解分岐を薄くする。 | |
| -/ | |
| private lemma compute_xMin_eq_neg_one_of_R_eq_zero | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) | |
| (hLe : A ≤ D * K + gcdDA D A) : | |
| Impl.compute_xMin D A B K = -1 := by | |
| simp only [Impl.compute_xMin, hD, ↓reduceDIte, hA, hB, hK, hR0, hLe, Int.reduceNeg] | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、 | |
| 可解性 `hex`、`hRnz : Rof D A B ≠ 0`。 | |
| 主張: `R ≠ 0` の場合、実装側 `compute_xMin` は `D * uMinOf` を返す。 | |
| 内容: `compute_xMin` の `R ≠ 0` 分岐を `hbinRnz` に還元する。 | |
| 証明: 定義展開後に `hbinRnz` を `simpa` で読む。 | |
| 役割: `compute_xMin_eq_xMin` の `R ≠ 0` 分岐を helper に分離する。 | |
| -/ | |
| private lemma compute_xMin_eq_D_mul_uMinOf_of_R_ne_zero | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| (hRnz : Rof D A B ≠ 0) : | |
| Impl.compute_xMin D A B K = D * uMinOf D A B K hD hA hB hex := by | |
| simpa only [Impl.compute_xMin, hD, ↓reduceDIte, hA, hB, hK, hRnz, mul_eq_mul_left_iff] using | |
| hbinRnz hD hA hB hK hex hRnz | |
| /-- | |
| 入力/前提: `hex : HasUSolution D A B K hD hA hB` と、 | |
| 実装側が `D * uMinOf ... hex` を返す等式 `himpl`。 | |
| 主張: 実装 `compute_xMin` は仕様 `xMin` と一致する。 | |
| 内容: `xMin_eq_D_mul_uMinOf` を対称向きに使って `himpl` と連結する。 | |
| 証明: `trans` で示す。 | |
| 役割: `compute_xMin_eq_xMin_of_R_eq_zero` と `_of_R_ne_zero` の可解枝を共通化する。 | |
| -/ | |
| private lemma compute_xMin_eq_xMin_of_solution | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (hex : HasUSolution D A B K hD hA hB) | |
| (himpl : Impl.compute_xMin D A B K = D * uMinOf D A B K hD hA hB hex) : | |
| Impl.compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| simpa using | |
| (himpl.trans | |
| (Correctness.Internal.xMin_eq_D_mul_uMinOf | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hex).symm) | |
| /-- | |
| 入力/前提: `hno : ¬ ∃ u, SolU ... u` と、実装側が `-1` を返す等式 `himpl`。 | |
| 主張: 実装 `compute_xMin` は仕様 `xMin` と一致する。 | |
| 内容: `xMin_eq_neg_one_of_no_solution` を対称向きに使って `himpl` と連結する。 | |
| 証明: `trans` で示す。 | |
| 役割: `compute_xMin_eq_xMin_of_R_eq_zero` の不可解枝を薄くする。 | |
| -/ | |
| private lemma compute_xMin_eq_xMin_of_no_solution | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) | |
| (hno : ¬ ∃ u : Int, Search.Internal.SolU D A B K hD hA hB u) | |
| (himpl : Impl.compute_xMin D A B K = -1) : | |
| Impl.compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| simpa using | |
| (himpl.trans | |
| (Correctness.Internal.xMin_eq_neg_one_of_no_solution | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hno).symm) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、`hR0 : Rof D A B = 0`。 | |
| 主張: `R = 0` の場合、実装 `compute_xMin` は仕様 `xMin` と一致する。 | |
| 内容: `Bounds.Internal.exists_u_iff_DK_add_g_lt_A_of_R_eq_zero` で可解/不可解に分岐し、 | |
| 既存の計算側 helper と仕様側 helper を接続する。 | |
| 証明: `R=0` の存在条件を直接使い、2 ケースをそれぞれ `trans` で閉じる。 | |
| 役割: `compute_xMin_eq_xMin` 本体から `R = 0` 枝の分岐を外す。 | |
| -/ | |
| private lemma compute_xMin_eq_xMin_of_R_eq_zero | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hR0 : Rof D A B = 0) : | |
| Impl.compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| by_cases hcond : D * K + gcdDA D A < A | |
| · have hex : HasUSolution D A B K hD hA hB := by | |
| simpa using | |
| (Bounds.Internal.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).mpr hcond | |
| simpa using | |
| (compute_xMin_eq_xMin_of_solution | |
| (D := D) (A := A) (B := B) hD hA hB hex | |
| (compute_xMin_eq_D_mul_uMinOf_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hR0)) | |
| · simpa using | |
| (compute_xMin_eq_xMin_of_no_solution | |
| (D := D) (A := A) (B := B) hD hA hB | |
| (no_solU_of_not_DK_add_g_lt_A_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 hcond) | |
| (compute_xMin_eq_neg_one_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 | |
| (le_of_not_gt hcond))) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hK : 0 ≤ K`、`hRnz : Rof D A B ≠ 0`。 | |
| 主張: `R ≠ 0` の場合、実装 `compute_xMin` は仕様 `xMin` と一致する。 | |
| 内容: `R ≠ 0` の witness 構成から可解性を回収し、 | |
| 計算側/仕様側の `D * uMinOf` 表現をつなぐ。 | |
| 証明: `compute_xMin_eq_D_mul_uMinOf_of_R_ne_zero` と `xMin_eq_D_mul_uMinOf` を `trans` する。 | |
| 役割: `compute_xMin_eq_xMin` 本体から `R ≠ 0` 枝を外す。 | |
| -/ | |
| private lemma compute_xMin_eq_xMin_of_R_ne_zero | |
| (hD : 0 < D) (hA : 0 < A) (hB : 0 < B) (hK : 0 ≤ K) | |
| (hRnz : Rof D A B ≠ 0) : | |
| Impl.compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| rcases Bounds.Internal.exists_solU_lt_floor_ABK_div_R_plus_two_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hRnz with | |
| ⟨u, huSol, _⟩ | |
| have hex : HasUSolution D A B K hD hA hB := ⟨u, huSol⟩ | |
| simpa using | |
| (compute_xMin_eq_xMin_of_solution | |
| (D := D) (A := A) (B := B) hD hA hB hex | |
| (compute_xMin_eq_D_mul_uMinOf_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hex hRnz)) | |
| namespace Correctness | |
| /-- | |
| 入力/前提: `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) : | |
| Impl.compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| by_cases hR0 : Rof D A B = 0 | |
| · simpa using | |
| compute_xMin_eq_xMin_of_R_eq_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 | |
| · simpa using | |
| compute_xMin_eq_xMin_of_R_ne_zero | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hK hR0 | |
| end Correctness | |
| end ComputeCorrectness | |
| namespace Examples | |
| namespace Pow10 | |
| /-- | |
| 目的: `divmod_d19_7e37` で使う除数定数 `10^19` を名前付きで定義する。 | |
| 定義: `D19 := 10^19`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 定理文で巨大定数の反復記述を避け、可読性を保つ。 | |
| -/ | |
| private def D19 : Int := 10 ^ (19 : Nat) | |
| /-- | |
| 目的: `divmod_d16_128bit` の第1段で使う除数 `10^32` を定数として与える。 | |
| 定義: `D32 := 10^32`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 例 `D=10^32, A=2^64, B=2^64, K=1` の定理記述を簡潔にする。 | |
| -/ | |
| private def D32 : Int := 10 ^ (32 : Nat) | |
| /-- | |
| 目的: `divmod_d16_128bit` の第2段で使う除数 `10^16` を定数として与える。 | |
| 定義: `D16 := 10^16`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 例 `D=10^16, A=2^52, B=2^64, K=1` の定理記述を簡潔にする。 | |
| -/ | |
| private def D16 : Int := 10 ^ (16 : Nat) | |
| namespace Spec | |
| /-- | |
| 目的: 除数 `10^19` に対する標準の商・剰余ペアを定義する。 | |
| 定義: `divmod_d19 x := (x / D19, x % D19)`。 | |
| 入力/前提: `x : Int`。 | |
| 出力: 型 `Int × Int` の値 `(x / D19, x % D19)` を返す。 | |
| 役割: `divmod_d19_125bit` / `divmod_d19_127bit` / `divmod_d19_128bit` | |
| の正しさ定理における比較対象(仕様)として使う。 | |
| -/ | |
| def divmod_d19 (x : Int) : Int × Int := | |
| (x / D19, x % D19) | |
| /-- | |
| 目的: 除数 `10^32` に対する標準の商・剰余ペアを定義する。 | |
| 定義: `divmod_d32 x := (x / D32, x % D32)`。 | |
| 入力/前提: `x : Int`。 | |
| 出力: 型 `Int × Int` の値 `(x / D32, x % D32)` を返す。 | |
| 役割: `divmod_d16_128bit` 第1段の仕様(`10^32` での分解)として使う。 | |
| -/ | |
| def divmod_d32 (x : Int) : Int × Int := | |
| (x / D32, x % D32) | |
| /-- | |
| 目的: 除数 `10^16` に対する標準の商・剰余ペアを定義する。 | |
| 定義: `divmod_d16 x := (x / D16, x % D16)`。 | |
| 入力/前提: `x : Int`。 | |
| 出力: 型 `Int × Int` の値 `(x / D16, x % D16)` を返す。 | |
| 役割: `divmod_d16_128bit` 第2段の仕様(`10^16` での分解)として使う。 | |
| -/ | |
| def divmod_d16 (x : Int) : Int × Int := | |
| (x / D16, x % D16) | |
| /-- | |
| 目的: `x` を `10^32` と `10^16` で段階分解し、3ブロック `(q,s,t)` を得る。 | |
| 定義: まず `divmod_d32 x = (q,r)` を取り、次に `divmod_d16 r = (s,t)` として | |
| `(q,s,t)` を返す。 | |
| 入力/前提: `x : Int`。 | |
| 出力: 型 `Int × Int × Int` の値 `(q,s,t)` を返す。 | |
| 役割: `split3_d16_128bit` の仕様側参照として使う。 | |
| -/ | |
| def split3_d16 (x : Int) : (Int × Int × Int) := | |
| let (q, r) := divmod_d32 x | |
| let (s, t) := divmod_d16 r | |
| (q, s, t) | |
| end Spec | |
| namespace Impl | |
| namespace Internal | |
| /-- | |
| 目的: `D=10^16` の段で使うシフト定数 `2^52` を定数として与える。 | |
| 定義: `A52 := 2^52`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 例 `D=10^16, A=2^52, B=2^64, K=1` の定理記述を簡潔にする。 | |
| -/ | |
| private def A52 : Int := 2 ^ (52 : Nat) | |
| /-- | |
| 目的: `divmod_d19_125bit`, `divmod_d19_127bit` で使うシフト定数 `2^63` を名前付きで定義する。 | |
| 定義: `A63 := 2^63`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 近似商 `q = floor((floor(x/A)*M)/B)` の定数部を簡潔に書く。 | |
| -/ | |
| private def A63 : Int := 2 ^ (63 : Nat) | |
| /-- | |
| 目的: `divmod_d19_128bit` で使うシフト定数 `2^64` を名前付きで定義する。 | |
| 定義: `A64 := 2^64`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `divmod_d19_128bit` の証明で `A` 側定数を簡潔に書く。 | |
| -/ | |
| private def A64 : Int := 2 ^ (64 : Nat) | |
| /-- | |
| 目的: `divmod_d19_125bit`, `divmod_d19_127bit`, `divmod_d19_128bit` で使うシフト定数 `2^64` を名前付きで定義する。 | |
| 定義: `B64 := 2^64`(`Int`)。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 近似商計算および `compute_xMin` の評価式を簡潔にする。 | |
| -/ | |
| private def B64 : Int := 2 ^ (64 : Nat) | |
| /-- | |
| 目的: 125bit 版(最大 1 回補正)の想定範囲上端を定数として与える。 | |
| 定義: `xBound_d19_A63_B64_K1_125bit := 78312161395427422060000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x < xBound_d19_A63_B64_K1_125bit` から `Δ ≤ 1` を導く範囲条件として使う。 | |
| -/ | |
| private def xBound_d19_A63_B64_K1_125bit : Int := 78312161395427422060000000000000000000 | |
| /-- | |
| 目的: 127bit 版(最大 2 回補正)の想定範囲上端を定数として与える。 | |
| 定義: `xBound_d19_A63_B64_K2_127bit := 1086673501021195308190000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x < xBound_d19_A63_B64_K2_127bit` から `Δ ≤ 2` を導く範囲条件として使う。 | |
| -/ | |
| private def xBound_d19_A63_B64_K2_127bit : Int := 1086673501021195308190000000000000000000 | |
| /-- | |
| 目的: 128bit 版(最大 3 回補正)の想定範囲上端を定数として与える。 | |
| 定義: `xBound_d19_A64_B64_K3_128bit := 1164985662416622730250000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `x < xBound_d19_A64_B64_K3_128bit` から `Δ ≤ 3` を導く範囲条件として使う。 | |
| -/ | |
| private def xBound_d19_A64_B64_K3_128bit : Int := 1164985662416622730250000000000000000000 | |
| /-- | |
| 目的: 例 `D=10^32, A=2^64, B=2^64, K=1` の `x_min` 値を定数として与える。 | |
| 定義: `xBound_d32_A64_B64_K1_128bit := 508484200000000000000000000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `xMin` の具体値と `0 ≤ Δ ≤ 1` の範囲定理を記述する基準値。 | |
| -/ | |
| private def xBound_d32_A64_B64_K1_128bit : Int := 508484200000000000000000000000000000000 | |
| /-- | |
| 目的: 例 `D=10^16, A=2^52, B=2^64, K=1` の `x_min` 値を定数として与える。 | |
| 定義: `xBound_d16_A52_B64_K1_115bit := 70380273116483910380000000000000000`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `xMin` の具体値と `0 ≤ Δ ≤ 1` の範囲定理を記述する基準値。 | |
| -/ | |
| private def xBound_d16_A52_B64_K1_115bit : Int := 70380273116483910380000000000000000 | |
| end Internal | |
| /-- | |
| 目的: `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_A63_B64_K1_125bit_correct_on_range` で与える。 | |
| -/ | |
| def divmod_d19_A63_B64_K1_125bit (x : Int) : Int × Int := | |
| let M : Int := Internal.A63 * Internal.B64 / D19 | |
| let q : Int := ((x / Internal.A63) * M) / Internal.B64 | |
| let r : Int := x - q * D19 | |
| if D19 ≤ r then | |
| (q + 1, r - D19) | |
| 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_A63_B64_K2_127bit_correct_on_range` で与える。 | |
| -/ | |
| def divmod_d19_A63_B64_K2_127bit (x : Int) : Int × Int := | |
| let M : Int := Internal.A63 * Internal.B64 / D19 | |
| let q : Int := ((x / Internal.A63) * M) / Internal.B64 | |
| let r : Int := x - q * D19 | |
| if D19 * 2 ≤ r then | |
| (q + 2, r - D19 * 2) | |
| else if D19 ≤ r then | |
| (q + 1, r - D19) | |
| 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_A64_B64_K3_128bit_correct_on_range` で与える。 | |
| -/ | |
| def divmod_d19_A64_B64_K3_128bit (x : Int) : Int × Int := | |
| let M : Int := Internal.A64 * Internal.B64 / D19 | |
| let q : Int := ((x / Internal.A64) * M) / Internal.B64 | |
| let r : Int := x - q * D19 | |
| 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) | |
| /-- | |
| 目的: `D = 10^32` に対し、`2^128` 近似商から最大 1 回補正で `(q, r)` を返す。 | |
| 定義: `A = 2^64`, `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`。 | |
| 出力: 型 `Int × Int` の値 `(q, r)` を返す。 | |
| 役割: 例 `D=10^32, A=2^64, B=2^64, K=1` の実装計算を与える。 | |
| -/ | |
| def divmod_d32_A64_B64_K1_128bit (x : Int) : Int × Int := | |
| let M : Int := Internal.A64 * Internal.B64 / D32 | |
| let q : Int := ((x / Internal.A64) * M) / Internal.B64 | |
| let r : Int := x - q * D32 | |
| if D32 ≤ r then | |
| (q + 1, r - D32) | |
| else | |
| (q, r) | |
| /-- | |
| 目的: `D = 10^16` に対し、`2^115` 想定域で最大 1 回補正の `(q, r)` を返す。 | |
| 定義: `A = 2^52`, `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`。 | |
| 出力: 型 `Int × Int` の値 `(q, r)` を返す。 | |
| 役割: 例 `D=10^16, A=2^52, B=2^64, K=1` の実装計算を与える。 | |
| -/ | |
| private def divmod_d16_A52_B64_K1_115bit (x : Int) : Int × Int := | |
| let M : Int := Internal.A52 * Internal.B64 / D16 | |
| let q : Int := ((x / Internal.A52) * M) / Internal.B64 | |
| let r : Int := x - q * D16 | |
| if D16 ≤ r then | |
| (q + 1, r - D16) | |
| else | |
| (q, r) | |
| /-- | |
| 目的: 近似除算ベースで `x` を `(10^32, 10^16, 10^16)` の3ブロックへ分解する。 | |
| 定義: 第1段で `divmod_d32_A64_B64_K1_128bit x = (q,r)`、 | |
| 第2段で `divmod_d16_A52_B64_K1_115bit r = (s,t)` を計算し、`(q,s,t)` を返す。 | |
| 入力/前提: `x : Int`。 | |
| 出力: 型 `Int × Int × Int` の値 `(q,s,t)` を返す。 | |
| 役割: `split3_d16` 仕様に対応する実装側関数として使う。 | |
| -/ | |
| def split3_d16_128bit (x : Int) : Int × Int × Int := | |
| let (q, r) := divmod_d32_A64_B64_K1_128bit x | |
| let (s, t) := divmod_d16_A52_B64_K1_115bit r | |
| (q, s, t) | |
| end Impl | |
| namespace Correctness | |
| namespace Internal | |
| /-- | |
| 入力/前提: `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`)を与える補助補題。 | |
| -/ | |
| private 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` を導くための補助補題。 | |
| -/ | |
| private 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, Search.Internal.SolX D A B K hD hA hB z | |
| · intro hKx | |
| have hBddX : BddBelow ({z : Int | Search.Internal.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_A63_B64_K1_125bit` を返す。 | |
| 内容: 実装定義を計算評価して定数等式を得る。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: 125bit 範囲条件を `x < xMin(...,1)` に接続する。 | |
| -/ | |
| private lemma compute_xMin_D19_A63_B64_K1 : | |
| Impl.compute_xMin D19 Impl.Internal.A63 Impl.Internal.B64 1 = | |
| Impl.Internal.xBound_d19_A63_B64_K1_125bit := by | |
| set_option maxRecDepth 2000 in | |
| decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: 定数系 `(D19,A63,B64,K=2)` に対して `compute_xMin` は | |
| `xBound_d19_A63_B64_K2_127bit` を返す。 | |
| 内容: 実装定義を計算評価して定数等式を得る。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: 127bit 範囲条件を `x < xMin(...,2)` に接続する。 | |
| -/ | |
| private lemma compute_xMin_D19_A63_B64_K2 : | |
| Impl.compute_xMin D19 Impl.Internal.A63 Impl.Internal.B64 2 = | |
| Impl.Internal.xBound_d19_A63_B64_K2_127bit := by | |
| set_option maxRecDepth 2000 in | |
| decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: 定数系 `(D19,A64,B64,K=3)` に対して `compute_xMin` は | |
| `xBound_d19_128bit` を返す。 | |
| 内容: 実装定義を計算評価して定数等式を得る。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: 128bit 範囲条件を `x < xMin(...,3)` に接続する。 | |
| -/ | |
| private lemma compute_xMin_D19_A64_B64_K3 : | |
| Impl.compute_xMin D19 Impl.Internal.A64 Impl.Internal.B64 3 = | |
| Impl.Internal.xBound_d19_A64_B64_K3_128bit := by | |
| set_option maxRecDepth 2000 in | |
| decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `compute_xMin 10^32 2^64 2^64 1` は | |
| `508484200000000000000000000000000000000` を返す。 | |
| 内容: 実装定義を具体定数で計算評価した等式を与える。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: `xMin` の具体値定理と `Δ` の範囲定理の起点にする。 | |
| -/ | |
| private lemma compute_xMin_D32_A64_B64_K1 : | |
| Impl.compute_xMin D32 Impl.Internal.A64 Impl.Internal.B64 1 = | |
| Impl.Internal.xBound_d32_A64_B64_K1_128bit := by | |
| set_option maxRecDepth 4000 in | |
| decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `compute_xMin 10^16 2^52 2^64 1` は | |
| `70380273116483910380000000000000000` を返す。 | |
| 内容: 実装定義を具体定数で計算評価した等式を与える。 | |
| 証明: `decide` で計算して示す。 | |
| 役割: `xMin` の具体値定理と `Δ` の範囲定理の起点にする。 | |
| -/ | |
| private lemma compute_xMin_D16_A52_B64_K1 : | |
| Impl.compute_xMin D16 Impl.Internal.A52 Impl.Internal.B64 1 = | |
| Impl.Internal.xBound_d16_A52_B64_K1_115bit := by | |
| set_option maxRecDepth 4000 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` 仕様への橋渡しを共通化する。 | |
| -/ | |
| private 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 : Impl.compute_xMin D A B K = bound) | |
| (hx : x < bound) : | |
| x < xMin D A B K hD hA hB := by | |
| have hxMinEqComp : Impl.compute_xMin D A B K = xMin D A B K hD hA hB := by | |
| exact Correctness.compute_xMin_eq_xMin (D := D) (A := A) (B := B) (K := K) hD hA hB hK | |
| calc | |
| x < bound := hx | |
| _ = Impl.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` 範囲導出をまとめる。 | |
| -/ | |
| private 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 : Impl.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 | |
| refine ⟨?_, ?_⟩ | |
| · unfold Delta | |
| exact | |
| sub_nonneg.mpr | |
| (qApprox_le_trueQuot (D := D) (A := A) (B := B) hD hA hB hx0) | |
| · exact | |
| le_of_not_gt | |
| (not_lt_Delta_of_lt_xMin | |
| (D := D) (A := A) (B := B) (K := K) hD hA hB hx0 | |
| (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)) | |
| end Internal | |
| end Correctness | |
| /-- | |
| 入力/前提: `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` と真の商の関係を引く共通補題。 | |
| -/ | |
| private 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`)をまとめる。 | |
| -/ | |
| private 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`) から商の一致を導く共通補題。 | |
| -/ | |
| private 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` 形を共通で扱うための補助補題。 | |
| -/ | |
| private 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` で示す。 | |
| 役割: 補正後剰余が真の剰余に戻ることを共通で扱う補助補題。 | |
| -/ | |
| private 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` を共通に導く補助補題。 | |
| -/ | |
| private 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` で示す。 | |
| 役割: 上位分岐条件が偽であることを共通に導く補助補題。 | |
| -/ | |
| private 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) | |
| /-- | |
| 入力/前提: `δ = x/D - q`, `r = x%D + D*δ`, および `δ = k`。 | |
| 主張: `(q + k, r - D*k) = (x/D, x%D)`。 | |
| 内容: 商補正と剰余補正の標準形を同時に取り出す。 | |
| 証明: `q_add_eq_div_of_delta_eq` と `r_sub_D_mul_eq_rem_of_delta_eq` を組み合わせる。 | |
| 役割: `divmod_if1/2/3_correct_of_delta_le*` の各分岐末尾を共通化する。 | |
| -/ | |
| private lemma divmod_pair_eq_of_delta_eq | |
| {D x q r δ k : Int} | |
| (hDeltaEq : δ = x / D - q) | |
| (hrEq : r = x % D + D * δ) | |
| (hDeltaK : δ = k) : | |
| (q + k, r - D * k) = (x / D, x % D) := by | |
| simp only [ | |
| q_add_eq_div_of_delta_eq hDeltaEq hDeltaK, | |
| r_sub_D_mul_eq_rem_of_delta_eq hrEq hDeltaK | |
| ] | |
| /-- | |
| 入力/前提: `0 < D`, `r = x%D + D*δ`, `δ = k`, `k < m`。 | |
| 主張: `¬ D*m ≤ r`。 | |
| 内容: `r` が `x%D + D*k` 形なら、真の剰余 `x%D < D` から | |
| `m > k` の閾値には届かない。 | |
| 証明: `δ = k` で標準形に戻して既存補題へ送る。 | |
| 役割: `divmod_if1/2/3_correct_of_delta_le*` の非到達枝判定を共通化する。 | |
| -/ | |
| private lemma not_ge_D_mul_of_delta_eq | |
| {D x r δ k m : Int} | |
| (hD : 0 < D) | |
| (hrEq : r = x % D + D * δ) | |
| (hDeltaK : δ = k) | |
| (hkm : k < m) : | |
| ¬ D * m ≤ r := by | |
| exact | |
| not_ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := k) (m := m) | |
| hD hkm (r_eq_rem_add_D_mul_of_delta_eq hrEq hDeltaK) | |
| /-- | |
| 入力/前提: `0 < D`, `r = x%D + D*δ`, `δ = k`。 | |
| 主張: `D*k ≤ r`。 | |
| 内容: `r` が `x%D + D*k` 形なら、剰余の非負性から少なくとも `D*k` を含む。 | |
| 証明: `δ = k` で標準形に戻して既存補題へ送る。 | |
| 役割: `divmod_if1/2/3_correct_of_delta_le*` の到達枝判定を共通化する。 | |
| -/ | |
| private lemma ge_D_mul_of_delta_eq | |
| {D x r δ k : Int} | |
| (hD : 0 < D) | |
| (hrEq : r = x % D + D * δ) | |
| (hDeltaK : δ = k) : | |
| D * k ≤ r := by | |
| exact | |
| ge_D_mul_of_r_eq_rem_add_D_mul | |
| (D := D) (x := x) (r := r) (k := k) | |
| hD (r_eq_rem_add_D_mul_of_delta_eq hrEq hDeltaK) | |
| namespace Correctness | |
| namespace Internal | |
| /-- | |
| 入力/前提: `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` の分岐証明を共通化する。 | |
| -/ | |
| private 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 hNotGe : ¬ D ≤ r := by | |
| simpa only [mul_one] using | |
| (not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 0) (m := 1) | |
| hD hrEq hDelta0 (by decide)) | |
| simpa only [hNotGe, mul_zero, add_zero, sub_zero] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 0) | |
| hDeltaEq hrEq hDelta0) | |
| · have hGe : D ≤ r := by | |
| simpa only [mul_one] using | |
| (ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 1) | |
| hD hrEq hDelta1) | |
| simpa only [hGe, mul_one] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 1) | |
| hDeltaEq hrEq hDelta1) | |
| /-- | |
| 入力/前提: `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` の分岐証明を共通化する。 | |
| -/ | |
| private 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 hNotGe1 : ¬ D ≤ r := by | |
| simpa only [mul_one] using | |
| (not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 0) (m := 1) | |
| hD hrEq hDelta0 (by decide)) | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 0) (m := 2) | |
| hD hrEq hDelta0 (by decide) | |
| simpa only [hNotGe2, hNotGe1, mul_zero, add_zero, sub_zero] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 0) | |
| hDeltaEq hrEq hDelta0) | |
| · have hGe1 : D ≤ r := by | |
| simpa only [mul_one] using | |
| (ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 1) | |
| hD hrEq hDelta1) | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 1) (m := 2) | |
| hD hrEq hDelta1 (by decide) | |
| simpa only [hNotGe2, hGe1, mul_one] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 1) | |
| hDeltaEq hrEq hDelta1) | |
| · have hGe2 : D * 2 ≤ r := by | |
| exact | |
| ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 2) | |
| hD hrEq hDelta2 | |
| simpa only [hGe2] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 2) | |
| hDeltaEq hrEq hDelta2) | |
| /-- | |
| 入力/前提: `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` の分岐証明を共通化する。 | |
| -/ | |
| private 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 hNotGe1 : ¬ D ≤ r := by | |
| simpa only [mul_one] using | |
| (not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 0) (m := 1) | |
| hD hrEq hDelta0 (by decide)) | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 0) (m := 2) | |
| hD hrEq hDelta0 (by decide) | |
| have hNotGe3 : ¬ D * 3 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 0) (m := 3) | |
| hD hrEq hDelta0 (by decide) | |
| simpa only [hNotGe3, hNotGe2, hNotGe1, mul_zero, add_zero, sub_zero] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 0) | |
| hDeltaEq hrEq hDelta0) | |
| · have hGe1 : D ≤ r := by | |
| simpa only [mul_one] using | |
| (ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 1) | |
| hD hrEq hDelta1) | |
| have hNotGe2 : ¬ D * 2 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 1) (m := 2) | |
| hD hrEq hDelta1 (by decide) | |
| have hNotGe3 : ¬ D * 3 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 1) (m := 3) | |
| hD hrEq hDelta1 (by decide) | |
| simpa only [hNotGe3, hNotGe2, hGe1, mul_one] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 1) | |
| hDeltaEq hrEq hDelta1) | |
| · have hGe2 : D * 2 ≤ r := by | |
| exact | |
| ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 2) | |
| hD hrEq hDelta2 | |
| have hNotGe3 : ¬ D * 3 ≤ r := by | |
| exact | |
| not_ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 2) (m := 3) | |
| hD hrEq hDelta2 (by decide) | |
| simpa only [hNotGe3, hGe2] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 2) | |
| hDeltaEq hrEq hDelta2) | |
| · have hGe3 : D * 3 ≤ r := by | |
| exact | |
| ge_D_mul_of_delta_eq | |
| (D := D) (x := x) (r := r) (δ := δ) (k := 3) | |
| hD hrEq hDelta3 | |
| simpa only [hGe3] using | |
| (divmod_pair_eq_of_delta_eq | |
| (D := D) (x := x) (q := q) (r := r) (δ := δ) (k := 3) | |
| hDeltaEq hrEq hDelta3) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`、`0 ≤ Delta ≤ 1`、 | |
| 近似商の定義式 `hqDef`、および `r = x - q * D`。 | |
| 主張: 1 段補正版 `if D ≤ r then ... else ...` は真の `(x / D, x % D)` に一致する。 | |
| 内容: `Delta_eq_div_sub_q` と `sub_q_mul_eq_emod_add_Delta` を接続して | |
| `divmod_if1_correct_of_delta_le1` の前提を一括で組み立てる。 | |
| 証明: `delta` と `r` の標準形を作って共通補題へ渡す。 | |
| 役割: 1 段補正の例証明から中間補題 `hDeltaEq` / `hrEq` / `hCore` を取り除く。 | |
| -/ | |
| private lemma divmod_core_eq_of_delta_le1 | |
| {D A B x q r : Int} | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hDeltaNonneg : 0 ≤ Delta D A B x hD hA hB) | |
| (hDeltaLe1 : Delta D A B x hD hA hB ≤ 1) | |
| (hqDef : q = (((x / A) * ((A * B) / D)) / B)) | |
| (hr : r = x - q * D) : | |
| (if D ≤ r then (q + 1, r - D) else (q, r)) = (x / D, x % D) := by | |
| have hDeltaEq : Delta D A B x hD hA hB = x / D - q := by | |
| exact | |
| Delta_eq_div_sub_q | |
| (D := D) (A := A) (B := B) (x := x) (q := q) | |
| hD hA hB hqDef | |
| have hrEq : r = x % D + D * Delta D A B x hD hA hB := by | |
| calc | |
| r = x - q * D := hr | |
| _ = x % D + D * Delta D A B x hD hA hB := by | |
| simpa only [hqDef] using | |
| (sub_q_mul_eq_emod_add_Delta | |
| (D := D) (A := A) (B := B) (x := x) (q := q) | |
| hD hA hB hqDef) | |
| exact | |
| divmod_if1_correct_of_delta_le1 | |
| (D := D) (x := x) (q := q) (r := r) (δ := Delta D A B x hD hA hB) | |
| hD hDeltaNonneg hDeltaLe1 hDeltaEq hrEq | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hBound : compute_xMin D A B 1 = bound`, | |
| `hx0 : 0 ≤ x`, `hx : x < bound`、および `divmodImpl` の1段補正形への展開式。 | |
| 主張: `divmodImpl x = (x / D, x % D)`。 | |
| 内容: `delta_bounds_of_lt_compute_xMin_bound` で `0 ≤ Delta ≤ 1` を導き、 | |
| `q`,`r` の標準形を作って `divmod_core_eq_of_delta_le1` へ渡す。 | |
| 証明: 境界補題と 1 段補正共通補題の連結で示す。 | |
| 役割: 1 段補正の例定理から `Delta` 範囲導出と `q`,`r` 準備の重複を取り除く。 | |
| -/ | |
| private lemma divmod_eq_spec_of_delta_le1_on_range | |
| (divmodImpl : Int → Int × Int) | |
| {D A B bound x : Int} | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hBound : Impl.compute_xMin D A B 1 = bound) | |
| (hx0 : 0 ≤ x) | |
| (hx : x < bound) | |
| (hDivmod : | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| divmodImpl x = if D ≤ r then (q + 1, r - D) else (q, r)) : | |
| divmodImpl x = (x / D, x % D) := by | |
| rcases | |
| delta_bounds_of_lt_compute_xMin_bound | |
| (D := D) (A := A) (B := B) (K := 1) (x := x) | |
| (bound := bound) hD hA hB (by decide) hx0 hBound hx | |
| with ⟨hDeltaNonneg, hDeltaLe1⟩ | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| have hqDef : q = (((x / A) * ((A * B) / D)) / B) := by | |
| simp [M, q] | |
| have hDivmod' : | |
| divmodImpl x = if D ≤ r then (q + 1, r - D) else (q, r) := by | |
| simpa [M, q, r] using hDivmod | |
| exact | |
| hDivmod'.trans | |
| (divmod_core_eq_of_delta_le1 | |
| (D := D) (A := A) (B := B) (x := x) (q := q) (r := r) | |
| hD hA hB hDeltaNonneg hDeltaLe1 hqDef rfl) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`、`0 ≤ Delta ≤ 2`、 | |
| 近似商の定義式 `hqDef`、および `r = x - q * D`。 | |
| 主張: 2 段補正版 `if D*2 ≤ r then ... else if D ≤ r then ...` は真の商剰余に一致する。 | |
| 内容: `delta` と `r` の標準形を作って `divmod_if2_correct_of_delta_le2` に渡す。 | |
| 証明: 1 段版と同じく共通の前処理をまとめる。 | |
| 役割: 2 段補正の例証明から中間補題の重複を外す。 | |
| -/ | |
| private lemma divmod_core_eq_of_delta_le2 | |
| {D A B x q r : Int} | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hDeltaNonneg : 0 ≤ Delta D A B x hD hA hB) | |
| (hDeltaLe2 : Delta D A B x hD hA hB ≤ 2) | |
| (hqDef : q = (((x / A) * ((A * B) / D)) / B)) | |
| (hr : r = 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)) = (x / D, x % D) := by | |
| have hDeltaEq : Delta D A B x hD hA hB = x / D - q := by | |
| exact | |
| Delta_eq_div_sub_q | |
| (D := D) (A := A) (B := B) (x := x) (q := q) | |
| hD hA hB hqDef | |
| have hrEq : r = x % D + D * Delta D A B x hD hA hB := by | |
| calc | |
| r = x - q * D := hr | |
| _ = x % D + D * Delta D A B x hD hA hB := by | |
| simpa only [hqDef] using | |
| (sub_q_mul_eq_emod_add_Delta | |
| (D := D) (A := A) (B := B) (x := x) (q := q) | |
| hD hA hB hqDef) | |
| exact | |
| divmod_if2_correct_of_delta_le2 | |
| (D := D) (x := x) (q := q) (r := r) (δ := Delta D A B x hD hA hB) | |
| hD hDeltaNonneg hDeltaLe2 hDeltaEq hrEq | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hBound : compute_xMin D A B 2 = bound`, | |
| `hx0 : 0 ≤ x`, `hx : x < bound`、および `divmodImpl` の2段補正形への展開式。 | |
| 主張: `divmodImpl x = (x / D, x % D)`。 | |
| 内容: `delta_bounds_of_lt_compute_xMin_bound` で `0 ≤ Delta ≤ 2` を導き、 | |
| `q`,`r` の標準形を作って `divmod_core_eq_of_delta_le2` へ渡す。 | |
| 証明: 境界補題と 2 段補正共通補題の連結で示す。 | |
| 役割: `divmod_d19_A63_B64_K2_127bit_correct_on_range` の重複を取り除く。 | |
| -/ | |
| private lemma divmod_eq_spec_of_delta_le2_on_range | |
| (divmodImpl : Int → Int × Int) | |
| {D A B bound x : Int} | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hBound : Impl.compute_xMin D A B 2 = bound) | |
| (hx0 : 0 ≤ x) | |
| (hx : x < bound) | |
| (hDivmod : | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| divmodImpl x = | |
| if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r)) : | |
| divmodImpl x = (x / D, x % D) := by | |
| rcases | |
| delta_bounds_of_lt_compute_xMin_bound | |
| (D := D) (A := A) (B := B) (K := 2) (x := x) | |
| (bound := bound) hD hA hB (by decide) hx0 hBound hx | |
| with ⟨hDeltaNonneg, hDeltaLe2⟩ | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| have hqDef : q = (((x / A) * ((A * B) / D)) / B) := by | |
| simp [M, q] | |
| have hDivmod' : | |
| divmodImpl x = | |
| if D * 2 ≤ r then (q + 2, r - D * 2) | |
| else if D ≤ r then (q + 1, r - D) | |
| else (q, r) := by | |
| simpa [M, q, r] using hDivmod | |
| exact | |
| hDivmod'.trans | |
| (divmod_core_eq_of_delta_le2 | |
| (D := D) (A := A) (B := B) (x := x) (q := q) (r := r) | |
| hD hA hB hDeltaNonneg hDeltaLe2 hqDef rfl) | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`、`0 ≤ Delta ≤ 3`、 | |
| 近似商の定義式 `hqDef`、および `r = x - q * D`。 | |
| 主張: 3 段補正版 | |
| `if D*3 ≤ r then ... else if D*2 ≤ r then ... else if D ≤ r then ...` | |
| は真の商剰余に一致する。 | |
| 内容: `delta` と `r` の標準形を作って `divmod_if3_correct_of_delta_le3` に渡す。 | |
| 証明: 1 段版・2 段版と同型の前処理をまとめる。 | |
| 役割: 3 段補正の例証明から中間補題の重複を外す。 | |
| -/ | |
| private lemma divmod_core_eq_of_delta_le3 | |
| {D A B x q r : Int} | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hDeltaNonneg : 0 ≤ Delta D A B x hD hA hB) | |
| (hDeltaLe3 : Delta D A B x hD hA hB ≤ 3) | |
| (hqDef : q = (((x / A) * ((A * B) / D)) / B)) | |
| (hr : r = 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)) = (x / D, x % D) := by | |
| have hDeltaEq : Delta D A B x hD hA hB = x / D - q := by | |
| exact | |
| Delta_eq_div_sub_q | |
| (D := D) (A := A) (B := B) (x := x) (q := q) | |
| hD hA hB hqDef | |
| have hrEq : r = x % D + D * Delta D A B x hD hA hB := by | |
| calc | |
| r = x - q * D := hr | |
| _ = x % D + D * Delta D A B x hD hA hB := by | |
| simpa only [hqDef] using | |
| (sub_q_mul_eq_emod_add_Delta | |
| (D := D) (A := A) (B := B) (x := x) (q := q) | |
| hD hA hB hqDef) | |
| exact | |
| divmod_if3_correct_of_delta_le3 | |
| (D := D) (x := x) (q := q) (r := r) (δ := Delta D A B x hD hA hB) | |
| hD hDeltaNonneg hDeltaLe3 hDeltaEq hrEq | |
| /-- | |
| 入力/前提: `hD : 0 < D`, `hA : 0 < A`, `hB : 0 < B`, `hBound : compute_xMin D A B 3 = bound`, | |
| `hx0 : 0 ≤ x`, `hx : x < bound`、および `divmodImpl` の3段補正形への展開式。 | |
| 主張: `divmodImpl x = (x / D, x % D)`。 | |
| 内容: `delta_bounds_of_lt_compute_xMin_bound` で `0 ≤ Delta ≤ 3` を導き、 | |
| `q`,`r` の標準形を作って `divmod_core_eq_of_delta_le3` へ渡す。 | |
| 証明: 境界補題と 3 段補正共通補題の連結で示す。 | |
| 役割: `divmod_d19_A64_B64_K3_128bit_correct_on_range` の重複を取り除く。 | |
| -/ | |
| private lemma divmod_eq_spec_of_delta_le3_on_range | |
| (divmodImpl : Int → Int × Int) | |
| {D A B bound x : Int} | |
| (hD : 0 < D) | |
| (hA : 0 < A) | |
| (hB : 0 < B) | |
| (hBound : Impl.compute_xMin D A B 3 = bound) | |
| (hx0 : 0 ≤ x) | |
| (hx : x < bound) | |
| (hDivmod : | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| divmodImpl x = | |
| 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)) : | |
| divmodImpl x = (x / D, x % D) := by | |
| rcases | |
| delta_bounds_of_lt_compute_xMin_bound | |
| (D := D) (A := A) (B := B) (K := 3) (x := x) | |
| (bound := bound) hD hA hB (by decide) hx0 hBound hx | |
| with ⟨hDeltaNonneg, hDeltaLe3⟩ | |
| let M : Int := A * B / D | |
| let q : Int := ((x / A) * M) / B | |
| let r : Int := x - q * D | |
| have hqDef : q = (((x / A) * ((A * B) / D)) / B) := by | |
| simp [M, q] | |
| have hDivmod' : | |
| divmodImpl x = | |
| 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) := by | |
| simpa [M, q, r] using hDivmod | |
| exact | |
| hDivmod'.trans | |
| (divmod_core_eq_of_delta_le3 | |
| (D := D) (A := A) (B := B) (x := x) (q := q) (r := r) | |
| hD hA hB hDeltaNonneg hDeltaLe3 hqDef rfl) | |
| /-- | |
| 入力/前提: `hqr : Spec.divmod_d32 x = (q, r)`。 | |
| 主張: 仕様 `divmod_d32` から得た剰余 `r` は `0 ≤ r < D32` を満たす。 | |
| 内容: `r = x % D32` を取り出して、`Int.emod_nonneg` と `Int.emod_lt_of_pos` を適用する。 | |
| 証明: `Prod.snd` への射影と剰余の基本不等式で示す。 | |
| 役割: `split3_d16_128bit_correct_on_range` で第2段 `divmod_d16` の前提をまとめて供給する。 | |
| -/ | |
| private lemma spec_divmod_d32_rem_bounds | |
| {x q r : Int} | |
| (hqr : Spec.divmod_d32 x = (q, r)) : | |
| 0 ≤ r ∧ r < D32 := by | |
| have hD32 : 0 < D32 := by decide | |
| have hrEq : r = x % D32 := by | |
| symm | |
| simpa only [Spec.divmod_d32] using congrArg Prod.snd hqr | |
| constructor | |
| · simpa only [hrEq] using (Int.emod_nonneg x (ne_of_gt hD32)) | |
| · simpa only [hrEq] using (Int.emod_lt_of_pos x hD32) | |
| /-- | |
| 入力/前提: `hqr : Spec.divmod_d32 x = (q, r)`。 | |
| 主張: `divmod_d32` の剰余 `r` は第2段 `divmod_d16` の想定上界より小さい。 | |
| 内容: `r < D32` と具体定数不等式 `D32 < xBound_d16_A52_B64_K1_115bit` を連結する。 | |
| 証明: 剰余範囲補題と `decide` による定数比較で示す。 | |
| 役割: `split3_d16_128bit_correct_on_range` で第2段の利用域条件を 1 行で供給する。 | |
| -/ | |
| private lemma spec_divmod_d32_rem_lt_d16_bound | |
| {x q r : Int} | |
| (hqr : Spec.divmod_d32 x = (q, r)) : | |
| r < Impl.Internal.xBound_d16_A52_B64_K1_115bit := by | |
| exact lt_trans (spec_divmod_d32_rem_bounds hqr).2 (by decide) | |
| end Internal | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d19_A63_B64_K1_125bit`。 | |
| 主張: `divmod_d19_A63_B64_K1_125bit x = divmod_d19 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 1` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if1_correct_of_delta_le1` を適用して結論を得る。 | |
| 証明: 既存の共通補題を連結して示す。 | |
| 役割: `divmod_d19_A63_B64_K1_125bit` の利用域における正当性保証を与える。 | |
| -/ | |
| theorem divmod_d19_A63_B64_K1_125bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < Impl.Internal.xBound_d19_A63_B64_K1_125bit) : | |
| Impl.divmod_d19_A63_B64_K1_125bit x = Spec.divmod_d19 x := by | |
| have hD : 0 < D19 := by decide | |
| have hA : 0 < Impl.Internal.A63 := by decide | |
| have hB : 0 < Impl.Internal.B64 := by decide | |
| simpa only [Spec.divmod_d19, D19] using | |
| (Internal.divmod_eq_spec_of_delta_le1_on_range | |
| Impl.divmod_d19_A63_B64_K1_125bit | |
| (D := D19) (A := Impl.Internal.A63) (B := Impl.Internal.B64) | |
| (bound := Impl.Internal.xBound_d19_A63_B64_K1_125bit) | |
| hD hA hB Internal.compute_xMin_D19_A63_B64_K1 hx0 hx | |
| (by | |
| unfold Impl.divmod_d19_A63_B64_K1_125bit | |
| rfl)) | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d19_A63_B64_K2_127bit`。 | |
| 主張: `divmod_d19_A63_B64_K2_127bit x = divmod_d19 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 2` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if2_correct_of_delta_le2` を適用して結論を得る。 | |
| 証明: 既存の共通補題を連結して示す。 | |
| 役割: `divmod_d19_A63_B64_K2_127bit` の利用域における正当性保証を与える。 | |
| -/ | |
| theorem divmod_d19_A63_B64_K2_127bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < Impl.Internal.xBound_d19_A63_B64_K2_127bit) : | |
| Impl.divmod_d19_A63_B64_K2_127bit x = Spec.divmod_d19 x := by | |
| have hD : 0 < D19 := by decide | |
| have hA : 0 < Impl.Internal.A63 := by decide | |
| have hB : 0 < Impl.Internal.B64 := by decide | |
| simpa only [Spec.divmod_d19, D19] using | |
| (Internal.divmod_eq_spec_of_delta_le2_on_range | |
| Impl.divmod_d19_A63_B64_K2_127bit | |
| (D := D19) (A := Impl.Internal.A63) (B := Impl.Internal.B64) | |
| (bound := Impl.Internal.xBound_d19_A63_B64_K2_127bit) | |
| hD hA hB Internal.compute_xMin_D19_A63_B64_K2 hx0 hx | |
| (by | |
| unfold Impl.divmod_d19_A63_B64_K2_127bit | |
| rfl)) | |
| /-- | |
| 入力/前提: `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_A64_B64_K3_128bit` の利用域における正当性保証を与える。 | |
| -/ | |
| theorem divmod_d19_A64_B64_K3_128bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < Impl.Internal.xBound_d19_A64_B64_K3_128bit) : | |
| Impl.divmod_d19_A64_B64_K3_128bit x = Spec.divmod_d19 x := by | |
| have hD : 0 < D19 := by decide | |
| have hA : 0 < Impl.Internal.A64 := by decide | |
| have hB : 0 < Impl.Internal.B64 := by decide | |
| simpa only [Spec.divmod_d19, D19] using | |
| (Internal.divmod_eq_spec_of_delta_le3_on_range | |
| Impl.divmod_d19_A64_B64_K3_128bit | |
| (D := D19) (A := Impl.Internal.A64) (B := Impl.Internal.B64) | |
| (bound := Impl.Internal.xBound_d19_A64_B64_K3_128bit) | |
| hD hA hB Internal.compute_xMin_D19_A64_B64_K3 hx0 hx | |
| (by | |
| unfold Impl.divmod_d19_A64_B64_K3_128bit | |
| rfl)) | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d32_A64_B64_K1_128bit`。 | |
| 主張: `divmod_d32_A64_B64_K1_128bit x = divmod_d32 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 1` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if1_correct_of_delta_le1` を適用して結論を得る。 | |
| 証明: `delta_bounds_of_lt_compute_xMin_bound` と共通補題の連結で示す。 | |
| 役割: `D=10^32` の1段補正実装が仕様 `divmod_d32` と一致することを与える。 | |
| -/ | |
| theorem divmod_d32_A64_B64_K1_128bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < Impl.Internal.xBound_d32_A64_B64_K1_128bit) : | |
| Impl.divmod_d32_A64_B64_K1_128bit x = Spec.divmod_d32 x := by | |
| have hD : 0 < D32 := by decide | |
| have hA : 0 < Impl.Internal.A64 := by decide | |
| have hB : 0 < Impl.Internal.B64 := by decide | |
| simpa only [Spec.divmod_d32] using | |
| (Internal.divmod_eq_spec_of_delta_le1_on_range | |
| Impl.divmod_d32_A64_B64_K1_128bit | |
| (D := D32) (A := Impl.Internal.A64) (B := Impl.Internal.B64) | |
| (bound := Impl.Internal.xBound_d32_A64_B64_K1_128bit) | |
| hD hA hB Internal.compute_xMin_D32_A64_B64_K1 hx0 hx | |
| (by | |
| unfold Impl.divmod_d32_A64_B64_K1_128bit | |
| rfl)) | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d16_A52_B64_K1_115bit`。 | |
| 主張: `divmod_d16_A52_B64_K1_115bit x = divmod_d16 x`。 | |
| 内容: 境界条件から `0 ≤ Delta ≤ 1` を導き、`q`,`r` の形へ落とす。 | |
| その後に共通補題 `divmod_if1_correct_of_delta_le1` を適用して結論を得る。 | |
| 証明: `delta_bounds_of_lt_compute_xMin_bound` と共通補題の連結で示す。 | |
| 役割: `D=10^16` の1段補正実装が仕様 `divmod_d16` と一致することを与える。 | |
| -/ | |
| theorem divmod_d16_A52_B64_K1_115bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < Impl.Internal.xBound_d16_A52_B64_K1_115bit) : | |
| Impl.divmod_d16_A52_B64_K1_115bit x = Spec.divmod_d16 x := by | |
| have hD : 0 < D16 := by decide | |
| have hA : 0 < Impl.Internal.A52 := by decide | |
| have hB : 0 < Impl.Internal.B64 := by decide | |
| simpa only [Spec.divmod_d16] using | |
| (Internal.divmod_eq_spec_of_delta_le1_on_range | |
| Impl.divmod_d16_A52_B64_K1_115bit | |
| (D := D16) (A := Impl.Internal.A52) (B := Impl.Internal.B64) | |
| (bound := Impl.Internal.xBound_d16_A52_B64_K1_115bit) | |
| hD hA hB Internal.compute_xMin_D16_A52_B64_K1 hx0 hx | |
| (by | |
| unfold Impl.divmod_d16_A52_B64_K1_115bit | |
| rfl)) | |
| /-- | |
| 入力/前提: `hx0 : 0 ≤ x`, `hx : x < xBound_d32_A64_B64_K1_128bit`。 | |
| 主張: `split3_d16_128bit x = split3_d16 x`。 | |
| 内容: 第1段 `divmod_d32` の一致で得た剰余 `r` に対して | |
| `0 ≤ r < D32 < xBound_d16_A52_B64_K1_115bit` を示し、 | |
| 第2段 `divmod_d16` の一致を適用して三つ組を同一視する。 | |
| 証明: 2つの範囲内正当性定理と剰余の基本不等式を連結して示す。 | |
| 役割: 3ブロック分解実装 `split3_d16_128bit` の仕様一致を与える。 | |
| -/ | |
| theorem split3_d16_128bit_correct_on_range | |
| {x : Int} | |
| (hx0 : 0 ≤ x) | |
| (hx : x < Impl.Internal.xBound_d32_A64_B64_K1_128bit) : | |
| Impl.split3_d16_128bit x = Spec.split3_d16 x := by | |
| have h32 : Impl.divmod_d32_A64_B64_K1_128bit x = Spec.divmod_d32 x := | |
| divmod_d32_A64_B64_K1_128bit_correct_on_range hx0 hx | |
| unfold Impl.split3_d16_128bit Spec.split3_d16 | |
| rw [h32] | |
| cases hqr : Spec.divmod_d32 x with | |
| | mk q r => | |
| have h16 : | |
| Impl.divmod_d16_A52_B64_K1_115bit r = Spec.divmod_d16 r := by | |
| exact | |
| divmod_d16_A52_B64_K1_115bit_correct_on_range | |
| (Internal.spec_divmod_d32_rem_bounds hqr).1 | |
| (Internal.spec_divmod_d32_rem_lt_d16_bound hqr) | |
| simp [h16] | |
| end Correctness | |
| end Pow10 | |
| end Examples | |
| 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.Analysis.SpecialFunctions.Log.Base | |
| import Mathlib.Data.Nat.Fib.Zeckendorf | |
| import Mathlib.NumberTheory.Real.GoldenRatio | |
| namespace Fib | |
| /-! ### Binet formula and floor/log characterization -/ | |
| noncomputable section | |
| namespace LogPhi | |
| /-- | |
| 目的: `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)) | |
| /-- | |
| 目的: 黄金比を底とする対数 `logPhi` を定義する。 | |
| 定義: `logPhi x := Real.logb Real.goldenRatio x`。 | |
| 入力/前提: x : Real。 | |
| 出力: 型 `Real` の値を返す。 | |
| 役割: 添字 `k` を `floor(log_φ(...))` で記述する主定理の記号を固定する。 | |
| -/ | |
| def logPhi (x : Real) : Real := Real.logb Real.goldenRatio x | |
| namespace Internal | |
| /-- | |
| 入力/前提: 追加の仮定なし。 | |
| 主張: `sqrt 5` は正である。 | |
| 内容: `Real.sqrt_pos` を `5 > 0` に適用する。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 除算・乗除不等式変形(`div_le_iff₀`, `lt_div_iff₀`)の前提に使う。 | |
| -/ | |
| private lemma sqrt5_pos : 0 < Real.sqrt 5 := by | |
| positivity | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `logArg n` は正である。 | |
| 内容: `logArg` を展開し、`sqrt5_pos` と `(n : Real) + 1/2 > 0` の積として示す。 | |
| 証明: 式変形で示す。 | |
| 役割: `Real.le_logb_iff_rpow_le` など `logb` の正引数条件を満たす。 | |
| -/ | |
| private lemma logArg_pos (n : Nat) : 0 < logArg n := by | |
| unfold logArg | |
| positivity | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `k = floor(logPhi(logArg n))` の同値条件を区間不等式で与える。 | |
| 内容: `Int.floor_eq_iff` を適用し、`(k : Real)+1` を `(k+1 : Real)` に正規化する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: `floor` 記述から連続量の不等式記述への最初の変換を担う。 | |
| -/ | |
| private 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 | |
| simpa only using (Int.floor_eq_iff).1 hk.symm | |
| · intro hk | |
| exact ((Int.floor_eq_iff).2 (by simpa only using hk)).symm | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: `logPhi` の区間不等式と `phi` のべき不等式は同値である。 | |
| 内容: 底条件 `Real.one_lt_goldenRatio` と引数正条件 `logArg_pos` の下で、 | |
| `Real.le_logb_iff_rpow_le` と `Real.logb_lt_iff_lt_rpow` を往復適用する。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 対数表現から指数表現へ移る中核変換。 | |
| -/ | |
| private lemma logPhi_bounds_iff_pow_bounds (k n : Nat) : | |
| ((k : Real) ≤ logPhi (logArg n) ∧ logPhi (logArg n) < (k + 1 : Real)) ↔ | |
| (Real.goldenRatio ^ k ≤ logArg n ∧ | |
| logArg n < Real.goldenRatio ^ (k + 1)) := by | |
| have hpos := logArg_pos n | |
| constructor | |
| · rintro ⟨h1, h2⟩ | |
| exact ⟨ | |
| by | |
| simpa [Real.rpow_natCast] using | |
| (Real.le_logb_iff_rpow_le Real.one_lt_goldenRatio hpos).1 h1, | |
| by | |
| rw [← Real.rpow_natCast] | |
| simpa [Nat.cast_add, Nat.cast_one] using | |
| (Real.logb_lt_iff_lt_rpow Real.one_lt_goldenRatio hpos).1 h2⟩ | |
| · rintro ⟨h1, h2⟩ | |
| exact ⟨ | |
| (Real.le_logb_iff_rpow_le Real.one_lt_goldenRatio hpos).2 <| by | |
| simpa [Real.rpow_natCast] using h1, | |
| (Real.logb_lt_iff_lt_rpow Real.one_lt_goldenRatio hpos).2 <| by | |
| rw [← Real.rpow_natCast] at h2 | |
| simpa [Nat.cast_add, Nat.cast_one] using h2⟩ | |
| /-- | |
| 入力/前提: 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` に直接比較できる形へ変換する。 | |
| -/ | |
| private lemma pow_bounds_iff_shifted_bounds (k n : Nat) : | |
| (Real.goldenRatio ^ k ≤ logArg n ∧ | |
| logArg n < Real.goldenRatio ^ (k + 1)) ↔ | |
| (Real.goldenRatio ^ k / Real.sqrt 5 - (1 / 2 : Real) ≤ (n : Real) ∧ | |
| (n : Real) < | |
| Real.goldenRatio ^ (k + 1) / Real.sqrt 5 - (1 / 2 : Real)) := by | |
| constructor | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have h1' : | |
| Real.goldenRatio ^ k / Real.sqrt 5 ≤ (n : Real) + (1 / 2 : Real) := by | |
| exact (div_le_iff₀ sqrt5_pos).2 <| | |
| by simpa [logArg, one_div, mul_comm] using h1 | |
| linarith | |
| · have h2' : | |
| (n : Real) + (1 / 2 : Real) < | |
| Real.goldenRatio ^ (k + 1) / Real.sqrt 5 := by | |
| exact (lt_div_iff₀ sqrt5_pos).2 <| | |
| by simpa [logArg, one_div, mul_comm] using h2 | |
| linarith | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have h1' : | |
| Real.goldenRatio ^ k / Real.sqrt 5 ≤ (n : Real) + (1 / 2 : Real) := by | |
| linarith | |
| simpa [logArg, one_div, mul_comm] using (div_le_iff₀ sqrt5_pos).1 h1' | |
| · have h2' : | |
| (n : Real) + (1 / 2 : Real) < | |
| Real.goldenRatio ^ (k + 1) / Real.sqrt 5 := by | |
| linarith | |
| simpa [logArg, one_div, mul_comm] using (lt_div_iff₀ sqrt5_pos).1 h2' | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `fib n` は `phi^n/√5` の `1/2` 未満の誤差で近似される。 | |
| 内容: `Real.coe_fib_eq` の誤差項 `goldenConj^n/√5` を `|goldenConj| < 1` と | |
| `√5 > 2` で評価し、絶対値不等式から上下評価へ変換する。 | |
| 証明: `sqrt5_pos` を再利用しつつ、Binet 公式を直接展開して誤差項を評価する。 | |
| 役割: `shifted_bounds_iff_fib_bounds` で `fib` の上下界を供給する。 | |
| -/ | |
| private lemma fib_binet_bounds (n : Nat) : | |
| Real.goldenRatio ^ n / Real.sqrt 5 - (1 / 2 : Real) < (Nat.fib n : Real) ∧ | |
| (Nat.fib n : Real) < Real.goldenRatio ^ n / Real.sqrt 5 + (1 / 2 : Real) := by | |
| have habs_psi_lt_one : |Real.goldenConj| < (1 : Real) := by | |
| refine abs_lt.2 ?_ | |
| constructor | |
| · simpa only using Real.neg_one_lt_goldenConj | |
| · have : Real.goldenConj < 0 := by | |
| simpa only using Real.goldenConj_neg | |
| linarith | |
| have habs_psi_pow_le_one : |Real.goldenConj| ^ n ≤ (1 : Real) := by | |
| exact pow_le_one₀ (abs_nonneg Real.goldenConj) (le_of_lt habs_psi_lt_one) | |
| have hone_div_sqrt5_lt_half : (1 : Real) / Real.sqrt 5 < (1 : Real) / 2 := by | |
| simpa [one_div] using | |
| (one_div_lt_one_div_of_lt (show (0 : Real) < 2 by norm_num) <| | |
| show (2 : Real) < Real.sqrt 5 by | |
| refine (Real.lt_sqrt (show (0 : Real) ≤ 2 by norm_num)).2 ?_ | |
| norm_num) | |
| have habs_err_le : | |
| |Real.goldenConj ^ n / Real.sqrt 5| ≤ (1 : Real) / Real.sqrt 5 := by | |
| simpa [abs_div, abs_pow, abs_of_pos sqrt5_pos] using | |
| (div_le_div_of_nonneg_right habs_psi_pow_le_one (le_of_lt sqrt5_pos)) | |
| have herr : | |
| (Nat.fib n : Real) - Real.goldenRatio ^ n / Real.sqrt 5 = | |
| -(Real.goldenConj ^ n / Real.sqrt 5) := by | |
| have hsqrt5_ne : (Real.sqrt 5) ≠ 0 := ne_of_gt sqrt5_pos | |
| rw [show (Nat.fib n : Real) = | |
| (Real.goldenRatio ^ n - Real.goldenConj ^ n) / Real.sqrt 5 by | |
| simpa only using (Real.coe_fib_eq n)] | |
| field_simp [hsqrt5_ne] | |
| ring | |
| have hmain : | |
| (-(1 / 2 : Real) < (Nat.fib n : Real) - Real.goldenRatio ^ n / Real.sqrt 5) ∧ | |
| ((Nat.fib n : Real) - Real.goldenRatio ^ n / Real.sqrt 5 < (1 / 2 : Real)) := by | |
| refine abs_lt.mp ?_ | |
| rw [herr, abs_neg] | |
| exact lt_of_le_of_lt habs_err_le hone_div_sqrt5_lt_half | |
| constructor <;> linarith [hmain.1, hmain.2] | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `fib_binet_bounds` の下側評価を取り出す。 | |
| 内容: 連言の左成分を返すだけ。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `shifted_bounds_iff_fib_bounds` で下界のみ使う場面を簡潔化する。 | |
| -/ | |
| private lemma fib_binet_lower (n : Nat) : | |
| Real.goldenRatio ^ n / Real.sqrt 5 - (1 / 2 : Real) < (Nat.fib n : Real) := by | |
| exact (fib_binet_bounds n).1 | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `fib_binet_bounds` の上側評価を取り出す。 | |
| 内容: 連言の右成分を返すだけ。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `shifted_bounds_iff_fib_bounds` で上界のみ使う場面を簡潔化する。 | |
| -/ | |
| private lemma fib_binet_upper (n : Nat) : | |
| (Nat.fib n : Real) < Real.goldenRatio ^ n / Real.sqrt 5 + (1 / 2 : Real) := by | |
| exact (fib_binet_bounds n).2 | |
| /-- | |
| 入力/前提: k n : Nat。 | |
| 主張: 平行移動境界とフィボナッチ区間条件は同値である。 | |
| 内容: `fib_binet_lower/upper` を `k` と `k+1` に適用し、 | |
| `Nat` と `Real` のキャストを介して `fib k ≤ n < fib (k+1)` に読み替える。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 解析的不等式から最終的な離散条件(フィボナッチ区間)へ接続する。 | |
| -/ | |
| private lemma shifted_bounds_iff_fib_bounds (k n : Nat) : | |
| (Real.goldenRatio ^ k / Real.sqrt 5 - (1 / 2 : Real) ≤ (n : Real) ∧ | |
| (n : Real) < Real.goldenRatio ^ (k + 1) / Real.sqrt 5 - (1 / 2 : Real)) ↔ | |
| (Nat.fib k ≤ n ∧ n < Nat.fib (k + 1)) := by | |
| constructor | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · have hk_lt : (Nat.fib k : Real) < (n : Real) + 1 := by | |
| linarith [h1, fib_binet_upper k] | |
| exact Nat.lt_succ_iff.mp <| by | |
| exact_mod_cast (show (Nat.fib k : Real) < ((n + 1 : Nat) : Real) by | |
| simpa [Nat.cast_add, Nat.cast_one] using hk_lt) | |
| · exact_mod_cast (lt_trans h2 (fib_binet_lower (k + 1))) | |
| · intro h | |
| rcases h with ⟨h1, h2⟩ | |
| constructor | |
| · exact le_of_lt (lt_of_lt_of_le (fib_binet_lower k) (by exact_mod_cast h1)) | |
| · have hcast : ((n + 1 : Nat) : Real) ≤ (Nat.fib (k + 1) : Real) := by | |
| exact_mod_cast Nat.succ_le_of_lt h2 | |
| have hplus : | |
| ((n + 1 : Nat) : Real) < | |
| Real.goldenRatio ^ (k + 1) / Real.sqrt 5 + (1 / 2 : Real) := | |
| lt_of_le_of_lt hcast (fib_binet_upper (k + 1)) | |
| have hplus' : | |
| (n : Real) + 1 < | |
| Real.goldenRatio ^ (k + 1) / Real.sqrt 5 + (1 / 2 : Real) := by | |
| simpa [Nat.cast_add, Nat.cast_one] using hplus | |
| linarith | |
| end Internal | |
| /-- | |
| 入力/前提: 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)) ↔ | |
| (Nat.fib k ≤ n ∧ n < Nat.fib (k + 1)) := by | |
| rw [Internal.floor_logPhi_iff, Internal.logPhi_bounds_iff_pow_bounds, | |
| Internal.pow_bounds_iff_shifted_bounds, Internal.shifted_bounds_iff_fib_bounds] | |
| /-- | |
| 入力/前提: 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)) ↔ | |
| (Nat.fib k ≤ n ∧ n < Nat.fib (k + 1)) := by | |
| have hlog : | |
| logPhi (logArg n) = | |
| logPhi ((n : Real) + (1 / 2 : Real)) + logPhi (Real.sqrt 5) := by | |
| unfold logPhi logArg | |
| rw [Real.logb_mul (b := Real.goldenRatio) | |
| (x := Real.sqrt 5) (y := (n : Real) + (1 / 2 : Real))] | |
| · ac_rfl | |
| · exact ne_of_gt Internal.sqrt5_pos | |
| · positivity | |
| simpa only [one_div, hlog] using (floor_logPhi_iff_fib_bounds (k := k) (n := n)) | |
| namespace Internal | |
| /-- | |
| 入力/前提: 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)` の鎖を直接作る補助補題。 | |
| -/ | |
| private lemma phi_pow_succ_lt_fib_add_three (m : Nat) : | |
| Real.goldenRatio ^ (m + 1) < (Nat.fib (m + 3) : Real) := by | |
| have hphi_lt_two : Real.goldenRatio < 2 := by | |
| simpa only using Real.goldenRatio_lt_two | |
| have hfib_pos : (0 : Real) < (Nat.fib (m + 1) : Real) := by | |
| exact_mod_cast (Nat.fib_pos).2 (Nat.succ_pos m) | |
| calc | |
| Real.goldenRatio ^ (m + 1) = | |
| Real.goldenRatio * (Nat.fib (m + 1) : Real) + (Nat.fib m : Real) := by | |
| simpa only using (Real.goldenRatio_mul_fib_succ_add_fib m).symm | |
| _ < (2 : Real) * (Nat.fib (m + 1) : Real) + (Nat.fib m : Real) := by | |
| nlinarith [hphi_lt_two, hfib_pos] | |
| _ = (Nat.fib (m + 3) : Real) := by | |
| simp [two_mul, Nat.cast_add, Nat.fib_add_two, add_comm, add_left_comm] | |
| end Internal | |
| /-- | |
| 入力/前提: n : Nat。 | |
| 主張: `n < Nat.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 < Nat.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 hn_lt_pow : (n : Real) < Real.goldenRatio ^ (m + 1) := by | |
| rw [← Real.rpow_natCast] | |
| exact (Real.logb_lt_iff_lt_rpow Real.one_lt_goldenRatio hn_pos).1 <| | |
| by simpa [m] using (Nat.lt_floor_add_one (logPhi (n : Real))) | |
| have : (n : Real) < (Nat.fib (Nat.floor (logPhi (n : Real)) + 3) : Real) := by | |
| simpa [m] using lt_trans hn_lt_pow (Internal.phi_pow_succ_lt_fib_add_three m) | |
| exact_mod_cast this | |
| end LogPhi | |
| end /- noncomputable section -/ | |
| namespace Core | |
| namespace Internal | |
| /-- | |
| 目的: 二分探索で扱う Fibonacci 状態 `FibState` を表す。 | |
| フィールド: | |
| `i` : 現在の添字 | |
| `fi` : `Nat.fib i` の値 | |
| `fi1` : `Nat.fib (i + 1)` の値 | |
| 不変条件: 仕様補題では常に `fi = Nat.fib i` と `fi1 = Nat.fib (i + 1)` を維持する。 | |
| 役割: `fibst_add`・`fibst_dbl`・`greatestFibBinary_go` の再帰状態として用いる。 | |
| -/ | |
| @[ext] | |
| private structure FibState where | |
| i : Nat | |
| fi : Nat | |
| fi1 : Nat | |
| /-- | |
| 目的: `FibState` が Fibonacci 値を正しく保持している不変量 `FibState.Valid` を定義する。 | |
| 定義: `fi = Nat.fib i` かつ `fi1 = Nat.fib (i + 1)`。 | |
| 入力/前提: `t : FibState`。 | |
| 出力: 命題を返す。 | |
| 役割: `fibst_add`・`fibst_dbl`・`greatestFibBinary_go` の仕様補題で共通利用する。 | |
| -/ | |
| private def FibState.Valid (t : FibState) : Prop := | |
| t.fi = Nat.fib t.i ∧ t.fi1 = Nat.fib (t.i + 1) | |
| /-- | |
| 目的: `greatestFibBinary` の初期状態として使う単位状態 `fibst_one` を定義する。 | |
| 定義: `fibst_one = ⟨1, 1, 1⟩`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `FibState` の値を返す。 | |
| 役割: `greatestFibBinary` の開始状態を名前で固定し、仕様補題で再利用する。 | |
| -/ | |
| private def fibst_one : FibState := ⟨1, 1, 1⟩ | |
| /-- | |
| 目的: `greatestFibBinary_go` の失敗側で返す零状態 `fibst_zero` を定義する。 | |
| 定義: `fibst_zero = ⟨0, 0, 1⟩`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `FibState` の値を返す。 | |
| 役割: `greatestFibBinary_go_spec` の `fuel = 0` ケースと `fi > n` 分岐で共通利用する。 | |
| -/ | |
| private def fibst_zero : FibState := ⟨0, 0, 1⟩ | |
| /-- | |
| 目的: 加法更新 `fibst_add` を定義する。 | |
| 定義: 状態 `⟨i, Fib i, Fib (i+1)⟩` と `⟨j, Fib j, Fib (j+1)⟩` から | |
| 加法公式 | |
| `Fib (i+j) = Fib i * Fib (j+1) + (Fib (i+1) - Fib i) * Fib j`、 | |
| `Fib (i+j+1) = Fib (i+1) * Fib (j+1) + Fib i * Fib j` | |
| を用いて `⟨i+j, Fib (i+j), Fib (i+j+1)⟩` を返す。 | |
| 入力/前提: `ti tj : FibState`。 | |
| 出力: 型 `FibState` の値を返す。 | |
| 役割: `greatestFibBinary_go` で再帰結果に現在状態を合成する補助更新として使う。 | |
| -/ | |
| @[inline] | |
| private def fibst_add : FibState → FibState → FibState | |
| | ⟨i, fi, fi1⟩, ⟨j, fj, fj1⟩ => | |
| ⟨i + j, fi * fj1 + (fi1 - fi) * fj, fi1 * fj1 + fi * fj⟩ | |
| /-- | |
| 目的: 倍角更新 `fibst_dbl` を定義する。 | |
| 定義: 状態 `⟨i, Fib i, Fib (i+1)⟩` から | |
| 倍化公式 | |
| `Fib (2i) = Fib i * (2 * Fib (i+1) - Fib i)`、 | |
| `Fib (2i+1) = (Fib i)^2 + (Fib (i+1))^2` | |
| を用いて `⟨2*i, Fib (2*i), Fib (2*i+1)⟩` を返す。 | |
| 入力/前提: `t : FibState`。 | |
| 出力: 型 `FibState` の値を返す。 | |
| 役割: `greatestFibBinary_go` の再帰呼び出しで添字を倍化する補助更新として使う。 | |
| -/ | |
| @[inline] | |
| private def fibst_dbl : FibState → FibState | |
| | ⟨i, fi, fi1⟩ => | |
| ⟨2 * i, fi * (2 * fi1 - fi), fi * fi + fi1 * fi1⟩ | |
| /-- | |
| 目的: 三つ組状態に対する二分探索再帰 `greatestFibBinary_go` を定義する。 | |
| 定義: 状態 `t = ⟨i, fi, fi1⟩` に対し、`fi ≤ n` なら | |
| `u := greatestFibBinary_go n fuel (fibst_dbl t)` を再帰計算し、 | |
| `v := fibst_add t u` の `fi` 成分が `≤ n` かで `v` または `u` を返す。 | |
| `fi > n` または燃料切れなら `⟨0,0,1⟩` を返す。 | |
| 入力/前提: `n : Nat`、再帰引数 `fuel : Nat` と状態 `t : FibState`。 | |
| 出力: 型 `FibState` の値を返す。 | |
| 役割: `greatestFibBinary` の計算本体として、`fib k ≤ n` を満たす最大添字候補 `k` を構成する。 | |
| -/ | |
| private def greatestFibBinary_go (n : Nat) : | |
| Nat → FibState → FibState | |
| | 0, _t => fibst_zero | |
| | fuel+1, t => | |
| if _h0 : t.fi ≤ n then | |
| let u := greatestFibBinary_go n fuel (fibst_dbl t) | |
| let v := fibst_add t u | |
| if _h1 : v.fi ≤ n then | |
| v | |
| else | |
| u | |
| else | |
| fibst_zero | |
| end Internal | |
| /-- | |
| 目的: `Nat.greatestFib` の行列二分探索実装に与える燃料 `greatestFibBinaryFuel` を定義する。 | |
| 定義: `m := 2 * log2(n+1) + 3` とおき、 | |
| `greatestFibBinaryFuel n = log2 m + 1` と定める。 | |
| 入力/前提: `n : Nat`。 | |
| 出力: 型 `Nat` の燃料値を返す。 | |
| 役割: `greatestFibBinaryFuel_bound` で | |
| `greatestFib n < 2 * log2(n+1) + 3 < 2 ^ greatestFibBinaryFuel n` | |
| を示し、`greatestFibBinary_go_spec` の初期呼び出し条件 | |
| `greatestFib n < 1 * 2^fuel` を満たすために使う。 | |
| -/ | |
| def greatestFibBinaryFuel (n : Nat) : Nat := | |
| Nat.log2 (2 * Nat.log2 (n + 1) + 3) + 1 | |
| /-- | |
| 目的: `Nat.greatestFib` の二分探索実装 `greatestFibBinary` を定義する。 | |
| 定義: 初期状態 `Internal.fibst_one = ⟨1,1,1⟩ = ⟨1, Fib 1, Fib 2⟩` と | |
| 燃料 `greatestFibBinaryFuel n` を与え、`greatestFibBinary_go` の返す | |
| `FibState.i` 成分を結果とする。 | |
| 計算量比較(`Nat` の四則演算を単位コストとみなす): | |
| `Nat.greatestFib` は `findGreatest` による線形探索で判定回数 `Θ(n)`、 | |
| `greatestFibBinary` は燃料に比例して反復し判定回数 `O(log log n)`。 | |
| 入力/前提: `n : Nat`。 | |
| 出力: 型 `Nat` の値を返す。 | |
| 役割: `Nat.greatestFib` と同値な計算実装を与える。 | |
| -/ | |
| def greatestFibBinary (n : Nat) : Nat := | |
| (Internal.greatestFibBinary_go n (greatestFibBinaryFuel n) Internal.fibst_one).i | |
| namespace Internal | |
| /-- | |
| 入力/前提: `i j : Nat`。 | |
| 主張: `fib (i + j)` を `fib i`・`fib (i+1)`・`fib j`・`fib (j+1)` で表す。 | |
| 内容: `fibst_add` の `fi` 成分が加法公式と一致することを示す。 | |
| 証明: `i = 0` と `i = succ _` に分け、`Nat.fib_add` と | |
| `Nat.fib_add_two_sub_fib_add_one` で式変形する。 | |
| 役割: `fibst_add_valid` の第一成分に使う。 | |
| -/ | |
| private theorem fib_add_eq (i j : Nat) : | |
| Nat.fib (i + j) | |
| = Nat.fib i * Nat.fib (j + 1) | |
| + (Nat.fib (i + 1) - Nat.fib i) * Nat.fib j := by | |
| cases i with | |
| | zero => simp | |
| | succ i => | |
| simpa [Nat.fib_add_two_sub_fib_add_one, add_comm, add_left_comm] using (Nat.fib_add i j) | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `fibst_zero` は `FibState.Valid` を満たす。 | |
| 内容: 零状態が `⟨0, fib 0, fib 1⟩` に一致することを確認する。 | |
| 証明: 定義展開と `simp`。 | |
| 役割: `greatestFibBinary_go_spec` の燃料切れ・失敗分岐で使う。 | |
| -/ | |
| private theorem fibst_zero_valid : fibst_zero.Valid := by | |
| simp [FibState.Valid, fibst_zero] | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `fibst_one` は `FibState.Valid` を満たす。 | |
| 内容: 初期状態が `⟨1, fib 1, fib 2⟩` に一致することを確認する。 | |
| 証明: 定義展開と `simp`。 | |
| 役割: `greatestFibBinary_spec` の初期呼び出し条件で使う。 | |
| -/ | |
| private theorem fibst_one_valid : fibst_one.Valid := by | |
| simp [FibState.Valid, fibst_one] | |
| /-- | |
| 入力/前提: `t u : FibState` と、それぞれの `FibState.Valid`。 | |
| 主張: `fibst_add t u` も `FibState.Valid` を満たす。 | |
| 内容: 加法更新が添字 `i + j` に対応する Fibonacci 値を保つことを示す。 | |
| 証明: 各成分を `Nat.fib_add` と `fib_add_eq` に書き換える。 | |
| 役割: `greatestFibBinary_go_spec` で再帰結果に現在状態を合成する際に使う。 | |
| -/ | |
| private theorem fibst_add_valid {t u : FibState} (ht : t.Valid) (hu : u.Valid) : | |
| (fibst_add t u).Valid := by | |
| rcases t with ⟨i, fi, fi1⟩ | |
| rcases u with ⟨j, fj, fj1⟩ | |
| replace ht : fi = Nat.fib i ∧ fi1 = Nat.fib (i + 1) := by | |
| simpa [FibState.Valid] using ht | |
| rcases ht with ⟨rfl, rfl⟩ | |
| replace hu : fj = Nat.fib j ∧ fj1 = Nat.fib (j + 1) := by | |
| simpa [FibState.Valid] using hu | |
| rcases hu with ⟨rfl, rfl⟩ | |
| constructor | |
| · simpa [fibst_add] using (fib_add_eq i j).symm | |
| · simpa [fibst_add, add_assoc, add_comm, add_left_comm] using (Nat.fib_add i j).symm | |
| /-- | |
| 入力/前提: `t : FibState` と `t.Valid`。 | |
| 主張: `fibst_dbl t` も `FibState.Valid` を満たす。 | |
| 内容: 倍角更新が添字 `2 * i` に対応する Fibonacci 値を保つことを示す。 | |
| 証明: `Nat.fib_two_mul` と `Nat.fib_two_mul_add_one` を用いる。 | |
| 役割: `greatestFibBinary_go_spec` の再帰呼び出しに使う。 | |
| -/ | |
| private theorem fibst_dbl_valid {t : FibState} (ht : t.Valid) : | |
| (fibst_dbl t).Valid := by | |
| rcases t with ⟨i, fi, fi1⟩ | |
| replace ht : fi = Nat.fib i ∧ fi1 = Nat.fib (i + 1) := by | |
| simpa [FibState.Valid] using ht | |
| rcases ht with ⟨rfl, rfl⟩ | |
| constructor | |
| · simp [fibst_dbl, Nat.fib_two_mul] | |
| · simpa [pow_two, fibst_dbl, two_mul, add_assoc, add_comm, add_left_comm] using | |
| (Nat.fib_two_mul_add_one i).symm | |
| /-- | |
| 入力/前提: `m : Nat`。 | |
| 主張: `2^(m+1) ≤ fib (2*m+3)`。 | |
| 内容: `fib` が 2 ステップごとに少なくとも倍増することから、 | |
| `log2` ベースの燃料上界を支える整数評価を与える。 | |
| 証明: `m` に関する帰納法で、`fib (k+2) ≥ 2 * fib k` を使う。 | |
| 役割: `greatestFibBinaryFuel_bound` の中核評価として使う。 | |
| -/ | |
| private theorem two_pow_succ_le_fib_two_mul_add_three (m : Nat) : | |
| 2 ^ (m + 1) ≤ Nat.fib (2 * m + 3) := by | |
| induction m with | |
| | zero => decide | |
| | succ m ih => | |
| calc | |
| 2 ^ (m + 1 + 1) ≤ 2 * Nat.fib (2 * m + 3) := by | |
| simpa [pow_succ, Nat.mul_assoc, Nat.mul_left_comm, Nat.mul_comm] using | |
| Nat.mul_le_mul_left 2 ih | |
| _ ≤ Nat.fib (2 * m + 3) + Nat.fib (2 * m + 4) := by | |
| simpa [two_mul] using | |
| add_le_add_left (Nat.fib_le_fib_succ (n := 2 * m + 3)) (Nat.fib (2 * m + 3)) | |
| _ = Nat.fib (2 * (m + 1) + 3) := by simpa using (Nat.fib_add_two (n := 2 * m + 3)).symm | |
| /-- | |
| 入力/前提: `n : Nat`、`t : FibState` は `Valid`、かつ `greatestFib n < t.i * 2^fuel`。 | |
| 主張: `greatestFibBinary_go n fuel t` は `Valid` な状態を返し、その添字 `r.i` は | |
| `r.i ≤ greatestFib n < r.i + t.i` を満たす。 | |
| 内容: 戻り値が幅 `t.i` の区間の左端として `greatestFib n` を挟み込むことを示す。 | |
| 証明: `fuel` に関する帰納法で、再帰結果 `u` の区間を | |
| `u` または `fibst_add t u` のどちらに振り分ける。 | |
| 役割: `greatestFibBinary_spec` の核心仕様補題である。 | |
| -/ | |
| private theorem greatestFibBinary_go_spec (n fuel : Nat) : | |
| ∀ {t : FibState}, | |
| t.Valid → | |
| Nat.greatestFib n < t.i * 2 ^ fuel → | |
| (greatestFibBinary_go n fuel t).Valid | |
| ∧ (greatestFibBinary_go n fuel t).i ≤ Nat.greatestFib n | |
| ∧ Nat.greatestFib n < (greatestFibBinary_go n fuel t).i + t.i := by | |
| induction fuel with | |
| | zero => | |
| intro t ht hbound | |
| refine ⟨fibst_zero_valid, Nat.zero_le _, ?_⟩ | |
| simpa [greatestFibBinary_go, fibst_zero] using hbound | |
| | succ fuel ih => | |
| intro t ht hbound | |
| by_cases h0 : t.fi ≤ n | |
| · have hu := ih (t := fibst_dbl t) (fibst_dbl_valid ht) (by | |
| simpa [fibst_dbl, pow_succ, Nat.mul_assoc, Nat.mul_left_comm, Nat.mul_comm] using hbound) | |
| set u := greatestFibBinary_go n fuel (fibst_dbl t) | |
| set v := fibst_add t u | |
| have hv_valid : v.Valid := by | |
| simpa [v] using fibst_add_valid ht (by simpa [u] using hu.1) | |
| by_cases h1 : v.fi ≤ n | |
| · simpa [greatestFibBinary_go, h0, u, v, h1] using | |
| (⟨hv_valid, (Nat.le_greatestFib).2 (by simpa [hv_valid.1] using h1), | |
| by simpa [u, v, fibst_add, fibst_dbl, two_mul, add_assoc, add_comm] using hu.2.2⟩ : | |
| v.Valid ∧ v.i ≤ Nat.greatestFib n ∧ Nat.greatestFib n < v.i + t.i) | |
| · simpa [greatestFibBinary_go, h0, u, v, h1] using | |
| (⟨by simpa [u] using hu.1, hu.2.1, by simpa [u, v, fibst_add, add_comm] using | |
| (lt_of_not_ge fun hv_ge => | |
| h1 (by simpa [hv_valid.1] using (Nat.le_greatestFib).1 hv_ge) : | |
| Nat.greatestFib n < v.i)⟩ : | |
| u.Valid ∧ u.i ≤ Nat.greatestFib n ∧ Nat.greatestFib n < u.i + t.i) | |
| · simpa [greatestFibBinary_go, h0, fibst_zero] using | |
| (⟨fibst_zero_valid, Nat.zero_le _, | |
| by simpa [fibst_zero] using (Nat.greatestFib_lt).2 (by simpa [ht.1] using h0)⟩ : | |
| fibst_zero.Valid ∧ fibst_zero.i ≤ Nat.greatestFib n ∧ | |
| Nat.greatestFib n < fibst_zero.i + t.i) | |
| /-- | |
| 入力/前提: `n : Nat`。 | |
| 主張: 初期状態 `fibst_one` と燃料 `greatestFibBinaryFuel n` は | |
| `greatestFibBinary_go_spec` の上界条件を満たす。 | |
| 内容: まず `2^(log2(n+1)+1) ≤ fib (2*log2(n+1)+3)` を示して | |
| `greatestFib n < 2*log2(n+1)+3` を得た後、 | |
| `Nat.lt_log2_self` で `2*log2(n+1)+3 < 2^fuel` に持ち上げる。 | |
| 証明: `two_pow_succ_le_fib_two_mul_add_three`・`Nat.greatestFib_lt`・ | |
| `Nat.lt_log2_self` を組み合わせる。 | |
| 役割: `greatestFibBinary_spec` の初期呼び出し条件を供給する。 | |
| -/ | |
| private theorem greatestFibBinaryFuel_bound (n : Nat) : | |
| Nat.greatestFib n < fibst_one.i * 2 ^ greatestFibBinaryFuel n := by | |
| calc | |
| Nat.greatestFib n < 2 * Nat.log2 (n + 1) + 3 := by | |
| exact (Nat.greatestFib_lt).2 <| | |
| lt_of_lt_of_le | |
| (lt_trans (Nat.lt_succ_self n) Nat.lt_log2_self) | |
| (by simpa using two_pow_succ_le_fib_two_mul_add_three (Nat.log2 (n + 1))) | |
| _ < 2 ^ ((2 * Nat.log2 (n + 1) + 3).log2 + 1) := Nat.lt_log2_self | |
| _ = fibst_one.i * 2 ^ greatestFibBinaryFuel n := by | |
| simp [fibst_one, greatestFibBinaryFuel] | |
| end Internal | |
| /-- | |
| 入力/前提: `n : Nat`。 | |
| 主張: `greatestFibBinary n = Nat.greatestFib n`。 | |
| 内容: 二分探索実装 `greatestFibBinary` が、標準実装 `Nat.greatestFib` と | |
| 同じ最大添字を返すことを示す。 | |
| 証明: `greatestFibBinary_go_spec` を初期状態 `fibst_one` と | |
| 燃料上界 `greatestFibBinaryFuel_bound` に適用して | |
| `greatestFibBinary n ≤ Nat.greatestFib n < greatestFibBinary n + 1` を得る。 | |
| 後者を `Nat.lt_succ_iff` で `Nat.greatestFib n ≤ greatestFibBinary n` | |
| に直し、両側の大小関係から等式を結論する。 | |
| 役割: `greatestFibBinary` を `Nat.greatestFib` の正当な計算実装として公開する最終仕様定理。 | |
| -/ | |
| theorem greatestFibBinary_spec (n : Nat) : | |
| greatestFibBinary n = Nat.greatestFib n := by | |
| have hs := | |
| Internal.greatestFibBinary_go_spec n (greatestFibBinaryFuel n) (t := Internal.fibst_one) | |
| Internal.fibst_one_valid (Internal.greatestFibBinaryFuel_bound n) | |
| apply Nat.le_antisymm | |
| · simpa [greatestFibBinary] using hs.2.1 | |
| · exact Nat.lt_succ_iff.mp (by simpa [greatestFibBinary, Internal.fibst_one] using hs.2.2) | |
| end Core | |
| 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
| {"version": "1.1.0", | |
| "packagesDir": ".lake/packages", | |
| "packages": | |
| [{"url": "https://github.com/leanprover-community/mathlib4", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "4644b1dc054244e47557c6a68f1816b9c99c7cea", | |
| "name": "mathlib", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "master", | |
| "inherited": false, | |
| "configFile": "lakefile.lean"}, | |
| {"url": "https://github.com/leanprover-community/plausible", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "e84e3e16aea6b72cc5d311ca1bb25caad417e162", | |
| "name": "plausible", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "main", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}, | |
| {"url": "https://github.com/leanprover-community/LeanSearchClient", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "c5d5b8fe6e5158def25cd28eb94e4141ad97c843", | |
| "name": "LeanSearchClient", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "main", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}, | |
| {"url": "https://github.com/leanprover-community/import-graph", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "f207d9fcf0cef00ba79962a33ef156061914d9c7", | |
| "name": "importGraph", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "main", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}, | |
| {"url": "https://github.com/leanprover-community/ProofWidgets4", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "2e58165a9dcdca9837b666528f974299ee1a51cc", | |
| "name": "proofwidgets", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "v0.0.92", | |
| "inherited": true, | |
| "configFile": "lakefile.lean"}, | |
| {"url": "https://github.com/leanprover-community/aesop", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "c3361708f266893de5d1769192b60d4b1831f2bb", | |
| "name": "aesop", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "master", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}, | |
| {"url": "https://github.com/leanprover-community/quote4", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "221e8088e3a066b8676dc471ff10638cf1c10835", | |
| "name": "Qq", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "master", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}, | |
| {"url": "https://github.com/leanprover-community/batteries", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover-community", | |
| "rev": "bd58e3506632241b59e406902d5e42b73cdeccce", | |
| "name": "batteries", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "main", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}, | |
| {"url": "https://github.com/leanprover/lean4-cli", | |
| "type": "git", | |
| "subDir": null, | |
| "scope": "leanprover", | |
| "rev": "3de531c1135f5e3a01f3ac04830996fda476b28e", | |
| "name": "Cli", | |
| "manifestFile": "lake-manifest.json", | |
| "inputRev": "v4.29.0-rc6", | |
| "inherited": true, | |
| "configFile": "lakefile.toml"}], | |
| "name": "divapprox2", | |
| "lakeDir": ".lake"} |
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-rc6 |
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 Fib | |
| namespace Mwf | |
| namespace Internal | |
| /-- | |
| 目的: 3 項の最大値を計算する。 | |
| 定義: `max (max a b) c`。 | |
| 入力/前提: `a b c : Int`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 場合分け側の補助的な最大値記法。 | |
| -/ | |
| @[simp] | |
| private def max3 (a b c : Int) : Int := max (max a b) c | |
| /-- | |
| 目的: 4 項の最大値を計算する。 | |
| 定義: `max3` を使った 4 項版 `max`。 | |
| 入力/前提: `a b c d : Int`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 場合分け後の候補値をまとめて比較する。 | |
| -/ | |
| @[simp] | |
| private def max4 (a b c d : Int) : Int := max (max3 a b c) d | |
| end Internal | |
| namespace Spec | |
| /-- | |
| 目的: 整数の床除算を `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 | |
| /-- | |
| 目的: 走査区間 `0 ≤ x < N` を有限集合で表す。 | |
| 定義: `Icc 0 (N-1)` を採用。 | |
| 入力/前提: N : Int、_hN : 0 < N、0 : Int。 | |
| 出力: 型 `Finset Int` の値を返す。 | |
| 役割: `mwf` を Finset 最大値として扱う土台。 | |
| -/ | |
| @[simp] | |
| noncomputable 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] | |
| noncomputable 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] | |
| noncomputable 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] | |
| noncomputable 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) | |
| end Spec | |
| namespace Internal | |
| /-- | |
| 入力/前提: N : Int、hN : 0 < N。 | |
| 主張: `0<N` なら `dom` は非空。 | |
| 内容: `0 ∈ Icc 0 (N-1)` を構成。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: `max'` 利用条件を満たす。 | |
| -/ | |
| private lemma dom_nonempty {N : Int} (hN : 0 < N) : (Spec.dom N hN).Nonempty := by | |
| exact ⟨0, Finset.mem_Icc.mpr ⟨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'` 利用条件を満たす。 | |
| -/ | |
| private lemma domLr_nonempty {L R : Int} (hLR : L < R) : (Spec.domLr L R hLR).Nonempty := by | |
| have hL : L ≤ R - 1 := by | |
| nlinarith [hLR] | |
| exact ⟨L, Finset.mem_Icc.mpr ⟨le_rfl, hL⟩⟩ | |
| /-- | |
| 入力/前提: `x` が区間 `domLr L R` に属する。 | |
| 主張: ある Nat 添字 `j < R-L` が存在して `x = L + j` と書ける。 | |
| 内容: 区間内の整数を左端からのオフセットへ戻す標準変換である。 | |
| 証明: `j = toNat (x-L)` と置き、`domLr` の上下界から範囲と復元式を示す。 | |
| 役割: 区間版 `argmax` 証明での `Int` と `Nat` の往復を簡潔にする。 | |
| -/ | |
| private lemma exists_nat_offset_of_mem_domLr | |
| {L R x : Int} (hLR : L < R) (hx : x ∈ Spec.domLr L R hLR) : | |
| ∃ j : Nat, j < Int.toNat (R - L) ∧ L + Int.ofNat j = x := by | |
| have hNI : 0 < R - L := by | |
| nlinarith [hLR] | |
| let j : Nat := Int.toNat (x - L) | |
| have hxSub0 : 0 ≤ x - L := by | |
| have hxL : L ≤ x := (Finset.mem_Icc.mp hx).1 | |
| linarith | |
| have hxSubLt : x - L < R - L := by | |
| have hxR : x ≤ R - 1 := (Finset.mem_Icc.mp hx).2 | |
| linarith | |
| have hjlt : j < Int.toNat (R - L) := by | |
| simp only [j] | |
| exact (Int.toNat_lt_toNat hNI).2 hxSubLt | |
| have hxj : L + Int.ofNat j = x := by | |
| have hxSubEq : Int.ofNat j = x - L := by | |
| simp only [j] | |
| exact Int.toNat_of_nonneg hxSub0 | |
| calc | |
| L + Int.ofNat j = L + (x - L) := by rw [hxSubEq] | |
| _ = x := by ring | |
| exact ⟨j, hjlt, hxj⟩ | |
| end Internal | |
| namespace Spec | |
| /-- | |
| 入力/前提: 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 | |
| rcases Internal.dom_nonempty hN with ⟨x, hx⟩ | |
| exact ⟨obj A B C D M x hM, Finset.mem_image.mpr ⟨x, 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 | |
| rcases Internal.domLr_nonempty hLR with ⟨x, hx⟩ | |
| exact ⟨obj A B C D M x hM, Finset.mem_image.mpr ⟨x, hx, rfl⟩⟩ | |
| end Spec | |
| /-- | |
| 目的: 問題値 `mwf` を定義する。 | |
| 定義: `img` の最大値 `max'` を返す。 | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: 全証明で保存・変形する中心量。 | |
| -/ | |
| @[simp] | |
| noncomputable def mwf (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : Int := | |
| let s := Spec.img N M A B C D hN hM | |
| s.max' (Spec.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] | |
| noncomputable def mwfLr (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : Int := | |
| let s := Spec.imgLr L R M A B C D hLR hM | |
| s.max' (Spec.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'` で取り出す基底。 | |
| -/ | |
| noncomputable def mwfLrArgDom (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : Finset Int := | |
| (Spec.domLr L R hLR).filter (fun x => Spec.obj A B C D M x hM = mwfLr L R M A B C D hLR hM) | |
| namespace Internal | |
| /-- | |
| 入力/前提: 有限集合 `s` と写像 `f`、および像 `s.image f` の非空性。 | |
| 主張: `s.image f` の `max'` は、ある `x ∈ s` の像 `f x` として実現される。 | |
| 内容: `Finset.max'_mem` と `Finset.mem_image` を組み合わせた汎用 witness 補題。 | |
| 証明: `max'` の所属を `image` の逆像へ戻す。 | |
| 役割: `mwf` / `mwfLr` の最大達成点の存在証明を共通化する。 | |
| -/ | |
| private lemma exists_mem_eq_max'_image | |
| {α β : Type _} [DecidableEq β] [LinearOrder β] | |
| (s : Finset α) (f : α → β) (hs : (s.image f).Nonempty) : | |
| ∃ x ∈ s, f x = (s.image f).max' hs := | |
| Finset.mem_image.mp (Finset.max'_mem (s.image f) hs) | |
| /-- | |
| 入力/前提: `0 < N`, `0 < M`。 | |
| 主張: `mwf` を達成する `x ∈ dom` が存在する。 | |
| 内容: `mwf` は `img` の `max'` なので、その値はある元の `obj` として実現される。 | |
| 証明: `Finset.max'_mem` で `img` への所属を得て、`Finset.mem_image` で逆像を取り出す。 | |
| 役割: `normalize_mwf_eq` などで最大達成点の witness を毎回展開しないための補助。 | |
| -/ | |
| private lemma exists_obj_eq_mwf | |
| (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| ∃ x ∈ Spec.dom N hN, Spec.obj A B C D M x hM = mwf N M A B C D hN hM := by | |
| simpa [mwf, Spec.img] using | |
| exists_mem_eq_max'_image | |
| (Spec.dom N hN) | |
| (fun x => Spec.obj A B C D M x hM) | |
| (Spec.img_nonempty (N := N) (M := M) (A := A) (B := B) (C := C) (D := D) hN 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'` 利用条件を満たす。 | |
| -/ | |
| private 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 | |
| rcases exists_mem_eq_max'_image | |
| (Spec.domLr L R hLR) | |
| (fun x => Spec.obj A B C D M x hM) | |
| (Spec.imgLr_nonempty (L := L) (R := R) (M := M) (A := A) (B := B) (C := C) (D := D) | |
| hLR hM) with ⟨x, hx⟩ | |
| exact ⟨x, by simpa [mwfLrArgDom, mwfLr, Spec.imgLr, Finset.mem_filter] using hx⟩ | |
| /-- | |
| 入力/前提: `L < R`。 | |
| 主張: 区間 `[L, R+1)` の定義域は、`[L, R)` に右端 `R` を 1 点追加したものに一致する。 | |
| 内容: `Icc L R = insert R (Icc L (R-1))` の有限集合版。 | |
| 証明: 要素所属を `simp` で展開し、境界条件を算術で整理する。 | |
| 役割: `mwfLr` / `mwfLrFloorProd` の「右端を 1 つ伸ばす」更新則の基礎。 | |
| -/ | |
| private lemma domLr_right_extend | |
| (L R : Int) (hLR : L < R) (hLR1 : L < R + 1) : | |
| Spec.domLr L (R + 1) hLR1 = | |
| insert R (Spec.domLr L R hLR) := by | |
| ext x | |
| simp [Spec.domLr] | |
| omega | |
| /-- | |
| 入力/前提: `L < R`, `0 < M`。 | |
| 主張: 区間像 `imgLr` は、右端 `R` の値を 1 点追加した像に一致する。 | |
| 内容: `domLr_right_extend` と `Finset.image_insert` を組み合わせたもの。 | |
| 証明: 定義を書き換えて `simp` する。 | |
| 役割: `mwfLr` の右端更新を `Finset.max'` の計算へ帰着する。 | |
| -/ | |
| private lemma imgLr_right_extend | |
| (L R M A B C D : Int) (hLR : L < R) (hLR1 : L < R + 1) (hM : 0 < M) : | |
| Spec.imgLr L (R + 1) M A B C D hLR1 hM = | |
| insert (Spec.obj A B C D M R hM) (Spec.imgLr L R M A B C D hLR hM) := by | |
| rw [Spec.imgLr, domLr_right_extend L R hLR hLR1, Finset.image_insert, Spec.imgLr] | |
| private lemma max'_congr_local {α : Type _} [LinearOrder α] | |
| {s t : Finset α} (hs : s.Nonempty) (ht : t.Nonempty) (h : s = t) : | |
| s.max' hs = t.max' ht := by | |
| subst h | |
| cases Subsingleton.elim hs ht | |
| rfl | |
| end Internal | |
| /-- | |
| 目的: `mwfLr` の最小 `argmax` を定義する。 | |
| 定義: `mwfLrArgDom` の `min'` を返す。 | |
| 入力/前提: L R M A B C D : Int、hLR : L < R、hM : 0 < M。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `max` と同時に `argmax`(同値時は最小)を得るための本体。 | |
| -/ | |
| noncomputable 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' (Internal.mwfLrArgDom_nonempty L R M A B C D hLR hM) | |
| /-- | |
| 目的: 区間版 mwf の最大値と `argmax` を同時に返す型を定義する。 | |
| フィールド: `max`, `argmax`。 | |
| 不変条件: `argmax` は `[L, R)` 内で `max` を達成する最小添字。 | |
| 役割: `mwfLrWithArgmax` の返り値型。 | |
| -/ | |
| @[ext] | |
| structure mwfWithArgResult 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。 | |
| 出力: 型 `mwfWithArgResult` の値を返す。 | |
| 役割: 区間最大値と最小達成点の同時計算インターフェース。 | |
| -/ | |
| noncomputable def mwfLrWithArgmax | |
| (L R M A B C D : Int) (hLR : L < R) (hM : 0 < M) : mwfWithArgResult := | |
| { max := mwfLr L R M A B C D hLR hM | |
| argmax := mwfLrArgmax L R M A B C D hLR hM } | |
| namespace Impl | |
| /-- | |
| 目的: 正規化後の `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 * Spec.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 * Spec.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 := Spec.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 := Spec.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 := | |
| Spec.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 | |
| namespace Internal | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 正規化仮定下で `Yn1 ≥ 0`。 | |
| 内容: 分子非負と `M>0` から `ediv_nonneg`。 | |
| 証明: 式変形で示す。 | |
| 役割: `step_reduce` の分岐前提を供給。 | |
| -/ | |
| private 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 Spec.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 | |
| 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` になる矛盾。 | |
| 証明: 反証法・式変形・既存補題の書き換えで示す。 | |
| -/ | |
| private 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 < Impl.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 : Impl.Yn1 N M C D hN hM = 0 := by | |
| simp only [Impl.Yn1, Impl.yOf, Spec.zfloorDiv, hCeq, zero_mul, zero_add, hdiv0] | |
| rw [hY0] at hYp | |
| exact (lt_irrefl (0 : Int)) hYp | |
| end Internal | |
| end Impl | |
| namespace Fuel | |
| /-- | |
| 目的: `m` から得られる反復回数上界(`greatestFibBinary m - 1`)。 | |
| 定義: `greatestFibBinary` から 1 引いた上界として停止到達回数に適用する | |
| (`m>0` では `Nat.greatestFib m - 1` と同値)。 | |
| 入力/前提: m : Nat。 | |
| 出力: 型 `Nat` の値を返す。 | |
| 役割: tex 側の「高々 `g(m)-1` 回で停止」と整合する上界を与える。 | |
| -/ | |
| def stepBoundOfM (m : Nat) : Nat := | |
| Fib.Core.greatestFibBinary m - 1 | |
| end Fuel | |
| namespace Impl | |
| /-- | |
| 目的: 商 `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 := Internal.hCpos_of_Y_ge_one N M C D hN hM _hC0 _hD0 _hDM hY1 | |
| Spec.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 := Internal.hCpos_of_Y_ge_one N M C D hN hM _hC0 _hD0 _hDM hY1 | |
| Spec.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) | |
| namespace Internal | |
| /-- | |
| 目的: 2状態の評価式同値を定義する。 | |
| 定義: `max(r, s+mwf)` の等式。 | |
| 入力/前提: S T : St。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 遷移の正しさ記述に使う述語。 | |
| -/ | |
| @[simp] | |
| private 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] | |
| private 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] | |
| private 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] | |
| private noncomputable 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] | |
| private noncomputable 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] | |
| private 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] | |
| private 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 (Internal.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] | |
| private 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 (Internal.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] | |
| private 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] | |
| private def step (S : St) : St := | |
| step_reduce (step_normalize S) | |
| /-- | |
| 目的: `mwf_iter_aux` は `mwf` 計算の反復補助関数を定義する。 | |
| 定義: `step` を高々 `fuel` 回だけ回し、`c=0` に到達した時点の `r` を返す。 | |
| 入力/前提: `fuel : Nat`、`U : St`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: `mwf_iter` の反復本体。 | |
| -/ | |
| @[simp] | |
| private 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 | |
| end Internal | |
| /-- | |
| 目的: `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 * Spec.zfloorDiv D M hM) 0 N M A B C D hN hM | |
| Internal.mwf_iter_aux (Fuel.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 := Spec.zfloorDiv (c * l + d) m hM | |
| let d' : Int := Spec.zfloorMod (c * l + d) m hM | |
| exact a * l + b * q + mwf_iter n m a b c d' hN hM | |
| end Impl | |
| namespace Examples | |
| namespace Internal | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `Nat.fib 40 = 102334155`。 | |
| 内容: Fibonacci 実装の既知値テスト。 | |
| 証明: `decide` で計算する。 | |
| 役割: `Fuel.stepBoundOfM` 周辺の回帰確認に使う。 | |
| -/ | |
| private lemma test_nat_fib_40 : | |
| Nat.fib 40 = 102334155 := by decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `stepBoundOfM 102334154 = 38`。 | |
| 内容: Fibonacci 境界の直前値に対する燃料上界の回帰テスト。 | |
| 証明: `decide` で計算する。 | |
| 役割: `stepBoundOfM` の閾値挙動を固定する。 | |
| -/ | |
| private lemma test_stepBoundOfM_lt : | |
| Fuel.stepBoundOfM 102334154 = 38 := by decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `stepBoundOfM 102334155 = 39`。 | |
| 内容: Fibonacci 境界値そのものに対する燃料上界の回帰テスト。 | |
| 証明: `decide` で計算する。 | |
| 役割: `stepBoundOfM` の境界一致を固定する。 | |
| -/ | |
| private lemma test_stepBoundOfM_eq : | |
| Fuel.stepBoundOfM 102334155 = 39 := by decide | |
| /-- | |
| 入力/前提: なし。 | |
| 主張: `stepBoundOfM 102334156 = 39`。 | |
| 内容: Fibonacci 境界を越えた直後の燃料上界の回帰テスト。 | |
| 証明: `decide` で計算する。 | |
| 役割: `stepBoundOfM` の単調性確認に使う。 | |
| -/ | |
| private lemma test_stepBoundOfM_gt : | |
| Fuel.stepBoundOfM 102334156 = 39 := by decide | |
| /-- | |
| 入力/前提: 具体的な小さい入力。 | |
| 主張: `Impl.mwfLr_iter` の結果が既知値 `41` に一致する。 | |
| 内容: 区間版反復実装の回帰テスト。 | |
| 証明: `decide` で計算する。 | |
| 役割: `mwfLr_iter_correct` の実装側を壊していないか確認する。 | |
| -/ | |
| private lemma test_mwfLr_iter : | |
| Impl.mwfLr_iter 0 10 7 3 2 5 4 (by decide) (by decide) = 41 := by | |
| set_option maxRecDepth 160 in decide | |
| /-- | |
| 入力/前提: 具体的な大きめ入力。 | |
| 主張: `Impl.mwf_iter` の結果が既知値 `215327987` に一致する。 | |
| 内容: 単区間版反復実装の回帰テスト。 | |
| 証明: `decide` で計算する。 | |
| 役割: `mwf_iter_correct` の実装側を壊していないか確認する。 | |
| -/ | |
| private lemma test_mwf_iter : | |
| Impl.mwf_iter (10^9) 102334155 (-433494437) 701408733 63245986 31415926 | |
| (by decide) (by decide) = 215327987 := by | |
| set_option maxRecDepth 950 in decide | |
| end Internal | |
| end Examples | |
| noncomputable section | |
| namespace Spec | |
| /-- | |
| 入力/前提: 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 | |
| simp only [obj, zfloorDiv, img, dom] | |
| 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 ⟨x, hx, rfl⟩) | |
| end Spec | |
| namespace Internal | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `C=0` なら `Yn1=0`。 | |
| 内容: `0≤D<M` から `D/M=0` を適用。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 退化ケースの停止判定。 | |
| -/ | |
| private 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) : | |
| Impl.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 [Impl.Yn1, Impl.yOf, Spec.zfloorDiv, hC, hdiv0] | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `dom` 上では `yOf ≥ 0`。 | |
| 内容: 分子非負と `M>0` から示す。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 商範囲 `0..Y` の下限側。 | |
| -/ | |
| private 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 : Spec.dom N hN, | |
| 0 ≤ Impl.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 [Impl.yOf, Spec.zfloorDiv, Spec.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` の上限側。 | |
| -/ | |
| private 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 : Spec.dom N hN, | |
| Impl.yOf M C D hM x ≤ Impl.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 [Impl.yOf, Spec.zfloorDiv, Spec.dom, Impl.Yn1, ge_iff_le] using hdivLe | |
| /-- | |
| 入力/前提: `x ∈ dom` かつ `Yn1 = 0`。 | |
| 主張: その点での `yOf` は 0。 | |
| 内容: `0 ≤ yOf x ≤ Yn1` を既存の範囲補題から得て、`Yn1 = 0` を代入する。 | |
| 証明: `yOf_nonneg` と `yOf_le_Yn1` を合わせて `le_antisymm`。 | |
| 役割: `mwf_yn1_zero` で各点の床除算項が消えることを共通化する。 | |
| -/ | |
| private lemma yOf_eq_zero_of_Y_eq_zero | |
| (N M C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hxDom : x ∈ Spec.dom N hN) (hY0 : Impl.Yn1 N M C D hN hM = 0) : | |
| Impl.yOf M C D hM x = 0 := by | |
| have hnonneg := yOf_nonneg N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxDom) | |
| have hleY := yOf_le_Yn1 N M C D hN hM hC0 hD0 hCM hDM (Subtype.mk x hxDom) | |
| rw [hY0] at hleY | |
| exact le_antisymm hleY hnonneg | |
| /-- | |
| 入力/前提: `x ∈ dom` かつ `Yn1 = 0`。 | |
| 主張: その点での `obj` は線形項 `A * x` に一致する。 | |
| 内容: `yOf_eq_zero_of_Y_eq_zero` により床除算項が消える。 | |
| 証明: `Spec.obj` を展開し、床除算値 0 を代入して整理する。 | |
| 役割: `mwf_yn1_zero` の端点評価と一般点上界を短くする。 | |
| -/ | |
| private lemma obj_eq_Ax_of_Y_eq_zero | |
| (N M A B C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hxDom : x ∈ Spec.dom N hN) (hY0 : Impl.Yn1 N M C D hN hM = 0) : | |
| Spec.obj A B C D M x hM = A * x := by | |
| have hy0 : | |
| Impl.yOf M C D hM x = 0 := | |
| yOf_eq_zero_of_Y_eq_zero N M C D x hN hM hC0 hD0 hCM hDM hxDom hY0 | |
| have hdiv0 : Spec.zfloorDiv (C * x + D) M hM = 0 := by | |
| simpa only [Impl.yOf, Spec.zfloorDiv] using hy0 | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * Spec.zfloorDiv (C * x + D) M hM := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = A * x := by simp only [hdiv0, mul_zero, add_zero] | |
| /-- | |
| 入力/前提: N M C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `dom` 上の床除算値は `0..Yn1` に入る。 | |
| 内容: 非負性と右端比較で上下界を同時に構成。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 値域制御の基礎。 | |
| -/ | |
| private 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 ∈ Spec.dom N hN, | |
| 0 ≤ Spec.zfloorDiv (C * x + D) M hM ∧ | |
| Spec.zfloorDiv (C * x + D) M hM ≤ Impl.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 [Spec.zfloorDiv, ge_iff_le, Impl.yOf] using h1 | |
| · have h2 := yOf_le_Yn1 N M C D hN hM hC0 hD0 _hCM _hDM (Subtype.mk x hx) | |
| simpa only [Spec.zfloorDiv, Impl.Yn1, Impl.yOf, ge_iff_le] using h2 | |
| /-- | |
| 入力/前提: `0 < M`、`y*M ≤ t ≤ y*M + M - 1`。 | |
| 主張: `⌊t/M⌋ = y`。 | |
| 内容: 床除算がちょうど `y` になるための標準的な上下界判定。 | |
| 証明: 上側は `t/M ≤ (y*M + M - 1)/M = y`、下側は `y ≤ t/M` を示して `le_antisymm` を適用する。 | |
| 役割: `iy_left` / `iy_right` で構成した点の `yOf` 計算を共通化する。 | |
| -/ | |
| private lemma zfloorDiv_eq_of_mul_bounds (M t y : Int) (hM : 0 < M) | |
| (hlow : y * M ≤ t) (hhigh : t ≤ y * M + M - 1) : | |
| Spec.zfloorDiv t M hM = y := by | |
| unfold Spec.zfloorDiv | |
| apply le_antisymm | |
| · have hdiv_le : t / M ≤ (y * M + M - 1) / M := | |
| Int.ediv_le_ediv hM hhigh | |
| 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 : (y * M + M - 1) / M = y := by | |
| calc | |
| (y * M + 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]) | |
| · exact (Int.le_ediv_iff_mul_le hM).2 (by simpa only [mul_comm] using hlow) | |
| /-- | |
| 入力/前提: `0 < N`, `0 < C`, `0 ≤ a`, `a < C * N`。 | |
| 主張: `⌊a/C⌋` は `dom N` に入る。 | |
| 内容: 非負な被除数を正の除数で割った商は、上界 `a < C*N` から `N-1` 以下に抑えられる。 | |
| 証明: `Int.ediv_nonneg` で下界を、`Int.ediv_le_iff_le_mul` で上界を示して `Finset.mem_Icc` に入れる。 | |
| 役割: `iy_right_mem_dom` と `iy_left_mem_dom` の共通末尾を吸収する。 | |
| -/ | |
| private lemma zfloorDiv_mem_dom_of_nonneg_lt_mul (N C a : Int) | |
| (hN : 0 < N) (hCpos : 0 < C) (ha_nonneg : 0 ≤ a) (ha_lt : a < C * N) : | |
| Spec.zfloorDiv a C hCpos ∈ Spec.dom N hN := by | |
| have hx0 : 0 ≤ Spec.zfloorDiv a C hCpos := by | |
| simpa only [Spec.zfloorDiv] using Int.ediv_nonneg ha_nonneg (le_of_lt hCpos) | |
| have hxN : Spec.zfloorDiv a C hCpos ≤ N - 1 := by | |
| have hlt : a < (N - 1) * C + C := by | |
| calc | |
| a < C * N := ha_lt | |
| _ = (N - 1) * C + C := by ring | |
| exact (Int.ediv_le_iff_le_mul hCpos).2 hlt | |
| exact Finset.mem_Icc.mpr ⟨hx0, hxN⟩ | |
| /-! | |
| ## 初期化 | |
| `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` が常に候補である事実を使う。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 状態法の開始点。 | |
| -/ | |
| private 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 * Spec.zfloorDiv D M hM) (0 + mwf N M A B C D hN hM) := by | |
| have hx0 : (0 : Int) ∈ Spec.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 : Spec.obj A B C D M 0 hM ≤ mwf N M A B C D hN hM := | |
| Spec.obj_le_mwf N M A B C D 0 hN hM hx0 | |
| have hbase : B * Spec.zfloorDiv D M hM ≤ mwf N M A B C D hN hM := by | |
| simpa only [Spec.zfloorDiv, mwf, Spec.img, Spec.obj, Spec.dom, mul_zero, zero_add] | |
| using hbase_obj | |
| simpa only [zero_add] using (max_eq_right hbase).symm | |
| /-! | |
| ## 正規化 | |
| `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` の商剰余分解を式変形。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 点ごとの正規化同値の核。 | |
| -/ | |
| private lemma normalize_obj_eq (A B C D M S x : Int) (hM : 0 < M) : | |
| S + Spec.obj A B C D M x hM = | |
| (Impl.normS S B D M hM) + Spec.obj (Impl.normA A B C M hM) B | |
| (Impl.normC C M hM) (Impl.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 Spec.obj Impl.normS Impl.normA Impl.normC Impl.normD Spec.zfloorDiv Spec.zfloorMod | |
| rw [hdiv] | |
| ring | |
| /-- | |
| 入力/前提: R S N M A B C D : Int、`0 < N`, `0 < M`。 | |
| 主張: `S + mwf` は正規化後の `normS + mwf` に一致する。 | |
| 内容: 正規化前後の最大達成点をそれぞれ 1 つ取り、`normalize_obj_eq` と `obj_le_mwf` を往復させる。 | |
| 証明: 両方向の不等式を最大達成点の witness で示し、`le_antisymm` で結ぶ。 | |
| 役割: `mwf_step_equiv` で正規化前後の値を直接つなぐ本体補題。 | |
| -/ | |
| private lemma normalize_mwf_eq | |
| (S N M A B C D : Int) | |
| (hN : 0 < N) (hM : 0 < M) : | |
| S + mwf N M A B C D hN hM = | |
| Impl.normS S B D M hM + | |
| mwf N M (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) hN hM := by | |
| rcases exists_obj_eq_mwf N M (Impl.normA A B C M hM) B | |
| (Impl.normC C M hM) (Impl.normD D M hM) hN hM with ⟨x1, hx1, hx1eq⟩ | |
| rcases exists_obj_eq_mwf N M A B C D hN hM with ⟨x0, hx0, hx0eq⟩ | |
| have hobj1_le : | |
| Spec.obj A B C D M x1 hM ≤ mwf N M A B C D hN hM := | |
| Spec.obj_le_mwf N M A B C D x1 hN hM hx1 | |
| have hobj0_le : | |
| Spec.obj (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) M x0 hM | |
| ≤ mwf N M (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) hN hM := | |
| Spec.obj_le_mwf N M (Impl.normA A B C M hM) B | |
| (Impl.normC C M hM) (Impl.normD D M hM) x0 hN hM hx0 | |
| have hle1 : | |
| Impl.normS S B D M hM + | |
| mwf N M (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) hN hM | |
| ≤ S + mwf N M A B C D hN hM := by | |
| calc | |
| Impl.normS S B D M hM + | |
| mwf N M (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) hN hM | |
| = | |
| Impl.normS S B D M hM + | |
| Spec.obj (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) M x1 hM := by | |
| rw [← hx1eq] | |
| _ = S + Spec.obj A B C D M x1 hM := by | |
| symm | |
| simpa only [Spec.obj, Spec.zfloorDiv, Impl.normS, Impl.normA, Spec.zfloorMod, | |
| Impl.normD] using normalize_obj_eq A B C D M S x1 hM | |
| _ ≤ S + mwf N M A B C D hN hM := by | |
| simpa only [add_comm] using add_le_add_left hobj1_le S | |
| have hle2 : | |
| S + mwf N M A B C D hN hM | |
| ≤ Impl.normS S B D M hM + | |
| mwf N M (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) hN hM := by | |
| calc | |
| S + mwf N M A B C D hN hM = S + Spec.obj A B C D M x0 hM := by rw [← hx0eq] | |
| _ = | |
| Impl.normS S B D M hM + | |
| Spec.obj (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) M x0 hM := by | |
| simpa only [Spec.obj, Spec.zfloorDiv, Impl.normS, Impl.normA, Spec.zfloorMod, | |
| Impl.normD] using normalize_obj_eq A B C D M S x0 hM | |
| _ ≤ Impl.normS S B D M hM + | |
| mwf N M (Impl.normA A B C M hM) B (Impl.normC C M hM) (Impl.normD D M hM) hN hM := by | |
| simpa only [add_comm] using add_le_add_left hobj0_le (Impl.normS S B D M hM) | |
| exact le_antisymm hle2 hle1 | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `Yn1=0` なら `mwf = max 0 (A*(N-1))`。 | |
| 内容: 商項が全点で 0 になることを利用。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 再帰停止時の閉形式。 | |
| -/ | |
| private 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 : (Impl.Yn1 N M C D hN hM) = 0) : | |
| mwf N M A B C D hN hM | |
| = | |
| max 0 (A * (N - 1)) := by | |
| have hx0 : (0 : Int) ∈ Spec.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 := Spec.obj_le_mwf N M A B C D 0 hN hM hx0 | |
| have hobj0 : Spec.obj A B C D M 0 hM = 0 := by | |
| simpa only [mul_zero] using | |
| obj_eq_Ax_of_Y_eq_zero N M A B C D 0 hN hM hC0 hD0 hCM hDM hx0 hY0 | |
| simpa only [hobj0] using hobj0_le | |
| have hxN1 : (N - 1 : Int) ∈ Spec.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 := Spec.obj_le_mwf N M A B C D (N - 1) hN hM hxN1 | |
| have hobjR : Spec.obj A B C D M (N - 1) hM = A * (N - 1) := by | |
| simpa using | |
| obj_eq_Ax_of_Y_eq_zero N M A B C D (N - 1) hN hM hC0 hD0 hCM hDM hxN1 hY0 | |
| simpa only [hobjR] using 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 | |
| (Spec.img N M A B C D hN hM).max' | |
| (Spec.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 := Spec.img N M A B C D hN hM) | |
| (H := Spec.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 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))) | |
| simpa only [obj_eq_Ax_of_Y_eq_zero N M A B C D x hN hM hC0 hD0 hCM hDM hxdom hY0] using hAx | |
| exact le_antisymm hUpper hLower | |
| /-- | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `iy_right` は常に `dom` に属する。 | |
| 内容: 端点分岐と除算不等式で区間内を示す。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `iy_right` を評価点として合法化。 | |
| -/ | |
| private 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 ≤ Impl.Yn1 N M C D hN hM) : | |
| Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY ∈ Spec.dom N hN := by | |
| by_cases hYn1 : y = Impl.Yn1 N M C D hN hM | |
| · have hxN1 : (N - 1 : Int) ∈ Spec.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 [Spec.dom, Impl.iy_right, hYn1, Impl.Yn1, Impl.yOf, Spec.zfloorDiv, ↓reduceDIte, | |
| Finset.mem_Icc, Int.sub_nonneg, le_refl, and_true, ge_iff_le] using hxN1 | |
| · have hy_lt : y < Impl.Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy => hYn1 hy) | |
| have hYpos : 0 < Impl.Yn1 N M C D hN hM := lt_of_le_of_lt hy0 hy_lt | |
| have hY1 : 1 ≤ Impl.Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hCpos : 0 < C := Impl.Internal.hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hY1 | |
| have hy1 : y + 1 ≤ Impl.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, Impl.Yn1, Impl.yOf, Spec.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 hmem : | |
| Spec.zfloorDiv (M * y + M - D - 1) C hCpos ∈ Spec.dom N hN := | |
| zfloorDiv_mem_dom_of_nonneg_lt_mul N C (M * y + M - D - 1) hN hCpos hnum_nonneg hnum_lt_CN | |
| have hYn1' : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Impl.Yn1, Impl.yOf, Spec.zfloorDiv] using hYn1 | |
| simpa only [Spec.dom, Impl.iy_right, Impl.Yn1, Impl.yOf, Spec.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` 再帰の値一致に必須。 | |
| -/ | |
| private 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 ≤ Impl.Yn1 N M C D hN hM) | |
| (hy_ne : y ≠ Impl.Yn1 N M C D hN hM) : | |
| Impl.yOf M C D hM (Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY) | |
| = y := by | |
| have hy_lt : y < Impl.Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy => hy_ne hy) | |
| have hYpos : 0 < Impl.Yn1 N M C D hN hM := lt_of_le_of_lt hy0 hy_lt | |
| have hY1 : 1 ≤ Impl.Yn1 N M C D hN hM := (Int.lt_iff_add_one_le).1 hYpos | |
| have hCpos : 0 < C := Impl.Internal.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, Impl.Yn1, Impl.yOf, Spec.zfloorDiv] using hy_ne | |
| have hiy : | |
| Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY | |
| = Spec.zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| simp only [Impl.iy_right, Impl.Yn1, Impl.yOf, Spec.zfloorDiv, hneq, ↓reduceDIte] | |
| rw [hiy] | |
| unfold Impl.yOf Spec.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] | |
| exact zfloorDiv_eq_of_mul_bounds M (C * (a / C) + D) y hM hmul_low | |
| (by simpa only [mul_comm] using hnum_up) | |
| /-- | |
| 入力/前提: N M C D y : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `iy_left` は常に `dom` に属する。 | |
| 内容: 端点分岐と除算不等式で区間内を示す。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: `iy_left` を評価点として合法化。 | |
| -/ | |
| private 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 ≤ Impl.Yn1 N M C D hN hM) : | |
| Impl.iy_left N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY ∈ Spec.dom N hN := by | |
| by_cases hY0 : y = 0 | |
| · have hx0 : (0 : Int) ∈ Spec.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 [Spec.dom, Impl.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 ≤ Impl.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 := Impl.Internal.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 [Impl.Yn1, Impl.yOf, Spec.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 hmem : | |
| Spec.zfloorDiv (M * y + C - D - 1) C hCpos ∈ Spec.dom N hN := | |
| zfloorDiv_mem_dom_of_nonneg_lt_mul N C (M * y + C - D - 1) hN hCpos hnum_nonneg hnum_lt_CN | |
| simpa only [Spec.dom, Impl.iy_left, hY0, ↓reduceDIte, Spec.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` 再帰の値一致に必須。 | |
| -/ | |
| private 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 ≤ Impl.Yn1 N M C D hN hM) | |
| (hy_ne : y ≠ 0) : | |
| Impl.yOf M C D hM (Impl.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 ≤ Impl.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 := Impl.Internal.hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hY1 | |
| have hiy : | |
| Impl.iy_left N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY | |
| = Spec.zfloorDiv (M * y + C - D - 1) C hCpos := by | |
| simp only [Impl.iy_left, hy_ne, ↓reduceDIte, Spec.zfloorDiv] | |
| rw [hiy] | |
| unfold Impl.yOf Spec.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 | |
| exact zfloorDiv_eq_of_mul_bounds M (C * (a / C) + D) y hM hmul_low | |
| (by simpa only [mul_comm] using hnum_up') | |
| /-- | |
| 入力/前提: `0 ≤ y < Yn1`。 | |
| 主張: `iy_right y` は右端候補点の床除算表示に一致する。 | |
| 内容: `iy_right` の `if` を非端点条件で展開した明示式。 | |
| 証明: `y ≠ Yn1` に直して `Impl.iy_right` をそのまま簡約する。 | |
| 役割: 右端側の再帰候補の `obj` 計算を explicit にする。 | |
| -/ | |
| private lemma iy_right_eq_floor_of_lt | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hCpos : 0 < C) (hy0 : 0 ≤ y) (hyY : y ≤ Impl.Yn1 N M C D hN hM) | |
| (hy_lt : y < Impl.Yn1 N M C D hN hM) : | |
| Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY = | |
| Spec.zfloorDiv (M * y + M - D - 1) C hCpos := by | |
| have hne : y ≠ Impl.Yn1 N M C D hN hM := ne_of_lt hy_lt | |
| have hneq' : y ≠ (C * (N - 1) + D) / M := by | |
| simpa only [ne_eq, Impl.Yn1, Impl.yOf, Spec.zfloorDiv] using hne | |
| unfold Impl.iy_right | |
| simp only [Impl.Yn1, Impl.yOf, Spec.zfloorDiv, hneq', ↓reduceDIte] | |
| /-- | |
| 入力/前提: `0 ≤ y < Yn1`。 | |
| 主張: `iy_right y` での `obj` は右端再帰側の `obj` に一致する。 | |
| 内容: 非端点 `y` を右側の再帰問題へ移す際の値保存。 | |
| 証明: `iy_right_eq_floor_of_lt` を代入して `obj` を整理する。 | |
| 役割: `mwf_yn1_pos_a_nonneg` の右側候補比較に使う。 | |
| -/ | |
| private lemma obj_iy_right_eq | |
| (N M A B C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hCpos : 0 < C) (hy0 : 0 ≤ y) (hyY : y ≤ Impl.Yn1 N M C D hN hM) | |
| (hy_lt : y < Impl.Yn1 N M C D hN hM) : | |
| Spec.obj B A M (M - D - 1) C y hCpos = | |
| Spec.obj A B C D M | |
| (Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY) hM := by | |
| let x : Int := Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY | |
| have hyOf : Impl.yOf M C D hM x = y := by | |
| exact yOf_iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hyY (ne_of_lt hy_lt) | |
| have hxDef : x = Spec.zfloorDiv (M * y + M - D - 1) C hCpos := | |
| iy_right_eq_floor_of_lt N M C D y hN hM hC0 hD0 hCM hDM hCpos hy0 hyY hy_lt | |
| have hyDiv : Spec.zfloorDiv (C * x + D) M hM = y := by | |
| simpa only [Spec.zfloorDiv, Impl.yOf] using hyOf | |
| have harg : M * y + (M - D - 1) = M * y + M - D - 1 := by ring | |
| calc | |
| Spec.obj B A M (M - D - 1) C y hCpos | |
| = B * y + A * Spec.zfloorDiv (M * y + (M - D - 1)) C hCpos := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = B * y + A * Spec.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 * Spec.zfloorDiv (C * x + D) M hM := by rw [hyDiv] | |
| _ = Spec.obj A B C D M x hM := by simp only [Spec.zfloorDiv, Spec.obj] | |
| /-- | |
| 入力/前提: `x ∈ dom` かつ `yOf x = Yn1`、さらに `A ≥ 0`。 | |
| 主張: `x` での `obj` は右端値 `A * (N - 1) + B * Yn1` 以下。 | |
| 内容: 上端に達した点では `x ≤ N - 1` だけで十分に上界が出る。 | |
| 証明: `x ≤ N - 1` を掛け算して `obj` を評価する。 | |
| 役割: 非負傾き分岐の端点ケースを閉じる。 | |
| -/ | |
| private lemma obj_le_right_of_y_eq_top | |
| (N M A B C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hAnonneg : 0 ≤ A) (hxDom : x ∈ Spec.dom N hN) | |
| (hyTop : Impl.yOf M C D hM x = Impl.Yn1 N M C D hN hM) : | |
| Spec.obj A B C D M x hM ≤ A * (N - 1) + B * Impl.Yn1 N M C D hN hM := by | |
| have hxLe : x ≤ N - 1 := (Finset.mem_Icc.mp hxDom).2 | |
| have hyDiv : Spec.zfloorDiv (C * x + D) M hM = Impl.Yn1 N M C D hN hM := by | |
| simpa only [Spec.zfloorDiv, Impl.yOf] using hyTop | |
| have hA_le : A * x ≤ A * (N - 1) := mul_le_mul_of_nonneg_left hxLe hAnonneg | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * Spec.zfloorDiv (C * x + D) M hM := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = A * x + B * Impl.Yn1 N M C D hN hM := by rw [hyDiv] | |
| _ ≤ A * (N - 1) + B * Impl.Yn1 N M C D hN hM := by nlinarith [hA_le] | |
| /-- | |
| 入力/前提: `yOf x = y` かつ `A ≥ 0`。 | |
| 主張: 元の `obj` は右側再帰問題の `obj` 以下。 | |
| 内容: 同じ `y` を持つ点を右側再帰状態へ写したときの基本比較。 | |
| 証明: 床除算の上界を使って `x` を `⌊(My+M-D-1)/C⌋` で抑える。 | |
| 役割: `mwf_yn1_pos_a_nonneg` の一般点を再帰問題へ落とす。 | |
| -/ | |
| private lemma obj_le_obj_right_rec_of_yOf | |
| (M A B C D x y : Int) (hM : 0 < M) (hCpos : 0 < C) (hAnonneg : 0 ≤ A) | |
| (hDiv : Impl.yOf M C D hM x = y) : | |
| Spec.obj A B C D M x hM ≤ Spec.obj B A M (M - D - 1) C y hCpos := by | |
| have hDiv' : Spec.zfloorDiv (C * x + D) M hM = y := by | |
| simpa only [Spec.zfloorDiv, Impl.yOf] using hDiv | |
| have hDivEq : (C * x + D) / M = y := by simpa only [Spec.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 ≤ Spec.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 * Spec.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 | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * y := by | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * Spec.zfloorDiv (C * x + D) M hM := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = A * x + B * y := by rw [hDiv'] | |
| _ ≤ A * Spec.zfloorDiv (M * y + M - D - 1) C hCpos + B * y := by nlinarith [hAub] | |
| _ = B * y + A * Spec.zfloorDiv (M * y + M - D - 1) C hCpos := by ring | |
| _ = Spec.obj B A M (M - D - 1) C y hCpos := by | |
| calc | |
| B * y + A * Spec.zfloorDiv (M * y + M - D - 1) C hCpos | |
| = B * y + A * Spec.zfloorDiv (M * y + (M - D - 1)) C hCpos := by rw [harg] | |
| _ = Spec.obj B A M (M - D - 1) C y hCpos := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| /-- | |
| 入力/前提: `0 ≤ y + 1 ≤ Yn1`。 | |
| 主張: `iy_left (y + 1)` は左端候補点の床除算表示に一致する。 | |
| 内容: 左側候補の explicit 形を `+1` 付きで取り出す補題。 | |
| 証明: `iy_left` を展開し、`C` での割り算に `+1` を移す。 | |
| 役割: 負傾き分岐の候補点計算に使う。 | |
| -/ | |
| private lemma iy_left_eq_floor_add_one | |
| (N M C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hCpos : 0 < C) | |
| (hy1_nonneg : 0 ≤ y + 1) (hy1_leYY : y + 1 ≤ Impl.Yn1 N M C D hN hM) | |
| (hy1_ne0 : y + 1 ≠ 0) : | |
| Impl.iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY = | |
| Spec.zfloorDiv (M * y + M - D - 1) C hCpos + 1 := by | |
| have hxDef0 : | |
| Impl.iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY = | |
| Spec.zfloorDiv (M * (y + 1) + C - D - 1) C hCpos := by | |
| simp only [Impl.iy_left, hy1_ne0, ↓reduceDIte, Spec.zfloorDiv] | |
| have hCne : C ≠ 0 := ne_of_gt hCpos | |
| calc | |
| Impl.iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY | |
| = Spec.zfloorDiv (M * (y + 1) + C - D - 1) C hCpos := hxDef0 | |
| _ = Spec.zfloorDiv ((M * y + M - D - 1) + C) C hCpos := by ring_nf | |
| _ = Spec.zfloorDiv (M * y + M - D - 1) C hCpos + 1 := by | |
| unfold Spec.zfloorDiv | |
| simpa only [add_comm, mul_comm, mul_one] using | |
| (Int.add_mul_ediv_right (M * y + M - D - 1) 1 hCne) | |
| /-- | |
| 入力/前提: `0 ≤ y ≤ Yn1 - 1`。 | |
| 主張: `iy_left (y + 1)` での `obj` は左側再帰候補の `obj` に一致する。 | |
| 内容: 負傾き側で使う左候補点の値保存。 | |
| 証明: `iy_left_eq_floor_add_one` を代入して `obj` を整理する。 | |
| 役割: `mwf_yn1_pos_a_neg` の左端候補比較に使う。 | |
| -/ | |
| private lemma obj_iy_left_eq | |
| (N M A B C D y : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hCpos : 0 < C) (_hy0 : 0 ≤ y) (_hyLePred : y ≤ Impl.Yn1 N M C D hN hM - 1) | |
| (hy1_nonneg : 0 ≤ y + 1) (hy1_leYY : y + 1 ≤ Impl.Yn1 N M C D hN hM) | |
| (hy1_ne0 : y + 1 ≠ 0) : | |
| (A + B) + Spec.obj B A M (M - D - 1) C y hCpos = | |
| Spec.obj A B C D M | |
| (Impl.iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY) hM := by | |
| let x : Int := Impl.iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY | |
| have hyOf : Impl.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 hxDef : | |
| x = Spec.zfloorDiv (M * y + M - D - 1) C hCpos + 1 := | |
| iy_left_eq_floor_add_one N M C D y hN hM hC0 hD0 hCM hDM hCpos hy1_nonneg hy1_leYY hy1_ne0 | |
| have hyDiv : Spec.zfloorDiv (C * x + D) M hM = y + 1 := by | |
| simpa only [Spec.zfloorDiv, Impl.yOf] using hyOf | |
| have harg : M * y + (M - D - 1) = M * y + M - D - 1 := by ring | |
| calc | |
| (A + B) + Spec.obj B A M (M - D - 1) C y hCpos | |
| = (A + B) + (B * y + A * Spec.zfloorDiv (M * y + M - D - 1) C hCpos) := by | |
| rw [show Spec.obj B A M (M - D - 1) C y hCpos = | |
| B * y + A * Spec.zfloorDiv (M * y + M - D - 1) C hCpos by | |
| calc | |
| Spec.obj B A M (M - D - 1) C y hCpos | |
| = B * y + A * Spec.zfloorDiv (M * y + (M - D - 1)) C hCpos := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = B * y + A * Spec.zfloorDiv (M * y + M - D - 1) C hCpos := by rw [harg]] | |
| _ = B * (y + 1) + A * (Spec.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 * Spec.zfloorDiv (C * x + D) M hM := by rw [hyDiv] | |
| _ = Spec.obj A B C D M x hM := by simp only [Spec.zfloorDiv, Spec.obj] | |
| /-- | |
| 入力/前提: `x ∈ dom` かつ `yOf x = 0`、さらに `A < 0`。 | |
| 主張: `x` での `obj` は `0` 以下。 | |
| 内容: 下端に達した点では負傾きゆえに `x ≥ 0` から上界 `0` が得られる。 | |
| 証明: `A * x ≤ 0` を示して `obj` を評価する。 | |
| 役割: 負傾き分岐の端点ケースを閉じる。 | |
| -/ | |
| private lemma obj_le_zero_of_y_eq_zero | |
| (N M A B C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hAneg : A < 0) (hxDom : x ∈ Spec.dom N hN) | |
| (hyZero : Impl.yOf M C D hM x = 0) : | |
| Spec.obj A B C D M x hM ≤ 0 := by | |
| have hx0 : 0 ≤ x := (Finset.mem_Icc.mp hxDom).1 | |
| have hyDiv : Spec.zfloorDiv (C * x + D) M hM = 0 := by | |
| simpa only [Spec.zfloorDiv, Impl.yOf] using hyZero | |
| have hAx : A * x ≤ 0 := mul_nonpos_of_nonpos_of_nonneg (le_of_lt hAneg) hx0 | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * Spec.zfloorDiv (C * x + D) M hM := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = A * x + B * 0 := by rw [hyDiv] | |
| _ ≤ 0 := by nlinarith [hAx] | |
| /-- | |
| 入力/前提: `yOf x = y` かつ `0 < y`、さらに `A < 0`。 | |
| 主張: 元の `obj` は左側再帰問題にシフト項 `A + B` を足した値以下。 | |
| 内容: 負傾き分岐で一般点を左側再帰問題へ移す基本比較。 | |
| 証明: 左候補点の explicit 形と `x` の下界から `obj` を整理する。 | |
| 役割: `mwf_yn1_pos_a_neg` の一般点処理に使う。 | |
| -/ | |
| private lemma obj_le_obj_left_rec_shift_of_yOf | |
| (M A B C D x y : Int) (hM : 0 < M) (hCpos : 0 < C) (hAneg : A < 0) | |
| (_hyPos : 0 < y) (hDiv : Impl.yOf M C D hM x = y) : | |
| Spec.obj A B C D M x hM ≤ | |
| (A + B) + Spec.obj B A M (M - D - 1) C (y - 1) hCpos := by | |
| have hDiv' : Spec.zfloorDiv (C * x + D) M hM = y := by | |
| simpa only [Spec.zfloorDiv, Impl.yOf] using hDiv | |
| have hDivEq : (C * x + D) / M = y := by simpa only [Spec.zfloorDiv] using hDiv' | |
| have hDivLe : y ≤ (C * x + D) / M := by simpa only [hDivEq] using le_rfl | |
| have hNumLow : y * M ≤ C * x + D := (Int.le_ediv_iff_mul_le hM).1 hDivLe | |
| have hLle : Spec.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 * Spec.zfloorDiv (M * y + C - D - 1) C hCpos := by | |
| have htmp : x * A ≤ Spec.zfloorDiv (M * y + C - D - 1) C hCpos * A := | |
| mul_le_mul_of_nonpos_right hLle (le_of_lt hAneg) | |
| simpa only [Spec.zfloorDiv, ge_iff_le, mul_comm] using htmp | |
| have hCne : C ≠ 0 := ne_of_gt hCpos | |
| have hFloor : | |
| Spec.zfloorDiv (M * y + C - D - 1) C hCpos | |
| = Spec.zfloorDiv (M * (y - 1) + M - D - 1) C hCpos + 1 := by | |
| calc | |
| Spec.zfloorDiv (M * y + C - D - 1) C hCpos | |
| = Spec.zfloorDiv ((M * (y - 1) + M - D - 1) + C) C hCpos := by ring_nf | |
| _ = Spec.zfloorDiv (M * (y - 1) + M - D - 1) C hCpos + 1 := by | |
| unfold Spec.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 : | |
| Spec.obj B A M (M - D - 1) C (y - 1) hCpos = | |
| B * (y - 1) + A * Spec.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 | |
| Spec.obj B A M (M - D - 1) C (y - 1) hCpos | |
| = B * (y - 1) + A * Spec.zfloorDiv (M * (y - 1) + (M - D - 1)) C hCpos := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = B * (y - 1) + A * Spec.zfloorDiv (M * (y - 1) + M - D - 1) C hCpos := by rw [harg] | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * y := by | |
| calc | |
| Spec.obj A B C D M x hM = A * x + B * Spec.zfloorDiv (C * x + D) M hM := by | |
| simp only [Spec.obj, Spec.zfloorDiv] | |
| _ = A * x + B * y := by rw [hDiv'] | |
| _ ≤ A * Spec.zfloorDiv (M * y + C - D - 1) C hCpos + B * y := by nlinarith [hAub] | |
| _ = B * y + A * (Spec.zfloorDiv (M * (y - 1) + M - D - 1) C hCpos + 1) := by | |
| rw [hFloor] | |
| ring | |
| _ = (A + B) + (B * (y - 1) + A * Spec.zfloorDiv (M * (y - 1) + M - D - 1) C hCpos) := by ring | |
| _ = (A + B) + Spec.obj B A M (M - D - 1) C (y - 1) hCpos := by rw [hObj2] | |
| /-- | |
| 入力/前提: `Yn1 > 0` と `C > 0`。 | |
| 主張: 右側の再帰問題の `mwf` は元の `mwf` 以下。 | |
| 内容: 各再帰側候補 `y` を `iy_right y` で元問題へ戻し、値保存で比較する。 | |
| 証明: `obj_iy_right_eq` と `Spec.obj_le_mwf` を各点に適用して `Finset.max'_le` を使う。 | |
| 役割: `mwf_yn1_pos_a_nonneg` の再帰側下界を短く書くための helper。 | |
| -/ | |
| private lemma mwf_right_rec_le | |
| (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 < Impl.Yn1 N M C D hN hM) (hCpos : 0 < C) : | |
| mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos ≤ | |
| mwf N M A B C D hN hM := by | |
| unfold mwf | |
| simp only [Spec.img, Spec.obj, Spec.zfloorDiv, Spec.dom] | |
| refine Finset.max'_le | |
| (s := Spec.img (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos) | |
| (H := Spec.img_nonempty | |
| (N := Impl.Yn1 N M C D hN hM) (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 ≤ Impl.Yn1 N M C D hN hM - 1 := (Finset.mem_Icc.mp hyDom).2 | |
| have hy_lt : y < Impl.Yn1 N M C D hN hM := by nlinarith | |
| have hy_leYY : y ≤ Impl.Yn1 N M C D hN hM := le_of_lt hy_lt | |
| let x : Int := Impl.iy_right N M C D y hN hM hC0 hD0 hCM hDM hy0 hy_leYY | |
| have hxDom : x ∈ Spec.dom N hN := | |
| iy_right_mem_dom N M C D y hN hM hC0 hD0 hCM hDM hy0 hy_leYY | |
| have hObjEq : Spec.obj B A M (M - D - 1) C y hCpos = Spec.obj A B C D M x hM := by | |
| simpa only [x] using | |
| obj_iy_right_eq N M A B C D y hN hM hC0 hD0 hCM hDM hCpos hy0 hy_leYY hy_lt | |
| exact hObjEq.symm ▸ Spec.obj_le_mwf N M A B C D x hN hM hxDom | |
| /-- | |
| 入力/前提: `x ∈ dom`、`Yn1 > 0`、`A ≥ 0`。 | |
| 主張: `x` での `obj` は「右端値」と「右側再帰 `mwf`」の最大以下。 | |
| 内容: `yOf x = Yn1` なら右端項、そうでなければ右側再帰項で抑える。 | |
| 証明: `floorDiv_range_bounds` で `yOf x` の範囲を取り、2 ケースに分けて既存補題を適用する。 | |
| 役割: `mwf_yn1_pos_a_nonneg` の各点上界を 1 本にまとめる。 | |
| -/ | |
| private lemma obj_le_nonneg_max | |
| (N M A B C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hYpos : 0 < Impl.Yn1 N M C D hN hM) (hCpos : 0 < C) (hAnonneg : 0 ≤ A) | |
| (hxDom : x ∈ Spec.dom N hN) : | |
| Spec.obj A B C D M x hM ≤ | |
| max | |
| (A * (N - 1) + B * Impl.Yn1 N M C D hN hM) | |
| (mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos) := by | |
| let y : Int := Impl.yOf M C D hM x | |
| rcases floorDiv_range_bounds N M C D hN hM hC0 hD0 hCM hDM x hxDom with ⟨hy0, hyY⟩ | |
| by_cases hyTop : y = Impl.Yn1 N M C D hN hM | |
| · exact le_trans | |
| (obj_le_right_of_y_eq_top N M A B C D x hN hM hAnonneg hxDom hyTop) | |
| (le_max_left _ _) | |
| · have hy_lt : y < Impl.Yn1 N M C D hN hM := lt_of_le_of_ne hyY (fun hy' => hyTop hy') | |
| have hyDomYY : y ∈ Spec.dom (Impl.Yn1 N M C D hN hM) hYpos := by | |
| exact Finset.mem_Icc.mpr ⟨hy0, by nlinarith [hy_lt]⟩ | |
| have hRecObj : | |
| Spec.obj B A M (M - D - 1) C y hCpos ≤ | |
| mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos := | |
| Spec.obj_le_mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) y hYpos hCpos hyDomYY | |
| have hObjLe : | |
| Spec.obj A B C D M x hM ≤ Spec.obj B A M (M - D - 1) C y hCpos := | |
| obj_le_obj_right_rec_of_yOf M A B C D x y hM hCpos hAnonneg rfl | |
| exact le_trans hObjLe (le_trans hRecObj (le_max_right _ _)) | |
| /-- | |
| 入力/前提: `0 ≤ D < M`。 | |
| 主張: `x = 0` での `obj` は 0 に等しい。 | |
| 内容: `D / M = 0` なので床除算項が消える。 | |
| 証明: `Int.ediv_eq_zero_of_lt_abs` で `zfloorDiv D M = 0` を示して代入する。 | |
| 役割: `mwf_yn1_pos_a_neg` の左端下界を短く書く。 | |
| -/ | |
| private lemma obj_zero_eq_zero | |
| (A B C D M : Int) (hM : 0 < M) (hD0 : 0 ≤ D) (hDM : D < M) : | |
| Spec.obj A B C D M 0 hM = 0 := by | |
| have hDdiv0 : Spec.zfloorDiv D M hM = 0 := by | |
| unfold Spec.zfloorDiv | |
| exact Int.ediv_eq_zero_of_lt_abs hD0 (by simpa only [abs_of_pos hM] using hDM) | |
| calc | |
| Spec.obj A B C D M 0 hM = A * 0 + B * Spec.zfloorDiv D M hM := by | |
| simp only [Spec.obj, mul_zero, Spec.zfloorDiv, zero_add] | |
| _ = A * 0 + B * 0 := by rw [hDdiv0] | |
| _ = 0 := by ring | |
| /-- | |
| 入力/前提: `Yn1 > 0` と `C > 0`。 | |
| 主張: 左側再帰 `mwf` にシフト `A + B` を足した値は元の `mwf` 以下。 | |
| 内容: 各再帰側候補 `y` を `iy_left (y+1)` で元問題へ戻し、値保存で比較する。 | |
| 証明: `obj_iy_left_eq` と `Spec.obj_le_mwf` を各点に適用し、最後に `nlinarith` で戻す。 | |
| 役割: `mwf_yn1_pos_a_neg` の再帰側下界を短く書くための helper。 | |
| -/ | |
| private lemma mwf_left_rec_shift_le | |
| (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 < Impl.Yn1 N M C D hN hM) (hCpos : 0 < C) : | |
| (A + B) + mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos ≤ | |
| mwf N M A B C D hN hM := by | |
| have hrecCore : | |
| mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos ≤ | |
| mwf N M A B C D hN hM - (A + B) := by | |
| unfold mwf | |
| simp only [Spec.img, Spec.obj, Spec.zfloorDiv, Spec.dom] | |
| refine Finset.max'_le | |
| (s := Spec.img (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos) | |
| (H := Spec.img_nonempty | |
| (N := Impl.Yn1 N M C D hN hM) (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 ≤ Impl.Yn1 N M C D hN hM - 1 := (Finset.mem_Icc.mp hyDom).2 | |
| have hy1_nonneg : 0 ≤ y + 1 := by nlinarith [hy0] | |
| have hy1_leYY : y + 1 ≤ Impl.Yn1 N M C D hN hM := by nlinarith [hyLePred] | |
| have hy1_ne0 : y + 1 ≠ 0 := by nlinarith [hy0] | |
| let x : Int := Impl.iy_left N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY | |
| have hxDom : x ∈ Spec.dom N hN := | |
| iy_left_mem_dom N M C D (y + 1) hN hM hC0 hD0 hCM hDM hy1_nonneg hy1_leYY | |
| have hObjEq : | |
| (A + B) + Spec.obj B A M (M - D - 1) C y hCpos = Spec.obj A B C D M x hM := by | |
| simpa only [x] using | |
| obj_iy_left_eq N M A B C D y hN hM hC0 hD0 hCM hDM hCpos hy0 hyLePred | |
| hy1_nonneg hy1_leYY hy1_ne0 | |
| have hplus : | |
| (A + B) + Spec.obj B A M (M - D - 1) C y hCpos ≤ mwf N M A B C D hN hM := | |
| hObjEq ▸ Spec.obj_le_mwf N M A B C D x hN hM hxDom | |
| nlinarith [hplus] | |
| nlinarith [hrecCore] | |
| /-- | |
| 入力/前提: `x ∈ dom`、`Yn1 > 0`、`A < 0`。 | |
| 主張: `x` での `obj` は `0` と左側再帰項付き候補の最大以下。 | |
| 内容: `yOf x = 0` なら 0 で抑え、そうでなければ左側再帰項へ落とす。 | |
| 証明: `floorDiv_range_bounds` で `yOf x` の範囲を取り、2 ケースに分けて既存補題を適用する。 | |
| 役割: `mwf_yn1_pos_a_neg` の各点上界を 1 本にまとめる。 | |
| -/ | |
| private lemma obj_le_neg_max | |
| (N M A B C D x : Int) (hN : 0 < N) (hM : 0 < M) | |
| (hC0 : 0 ≤ C) (hD0 : 0 ≤ D) (hCM : C < M) (hDM : D < M) | |
| (hYpos : 0 < Impl.Yn1 N M C D hN hM) (hCpos : 0 < C) (hAneg : A < 0) | |
| (hxDom : x ∈ Spec.dom N hN) : | |
| Spec.obj A B C D M x hM ≤ | |
| max 0 ((A + B) + mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos) := by | |
| let y : Int := Impl.yOf M C D hM x | |
| rcases floorDiv_range_bounds N M C D hN hM hC0 hD0 hCM hDM x hxDom with ⟨hy0, hyY⟩ | |
| by_cases hyZero : y = 0 | |
| · exact le_trans | |
| (obj_le_zero_of_y_eq_zero N M A B C D x hN hM hAneg hxDom hyZero) | |
| (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 ≤ Impl.Yn1 N M C D hN hM - 1 := sub_le_sub_right hyY 1 | |
| have hyDomYY : y - 1 ∈ Spec.dom (Impl.Yn1 N M C D hN hM) hYpos := | |
| Finset.mem_Icc.mpr ⟨hy1, hy1Le⟩ | |
| have hRecObj : | |
| Spec.obj B A M (M - D - 1) C (y - 1) hCpos ≤ | |
| mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos := | |
| Spec.obj_le_mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) (y - 1) hYpos hCpos hyDomYY | |
| have hObjLe : | |
| Spec.obj A B C D M x hM ≤ (A + B) + Spec.obj B A M (M - D - 1) C (y - 1) hCpos := | |
| obj_le_obj_left_rec_shift_of_yOf M A B C D x y hM hCpos hAneg hyPos rfl | |
| have hRecShift : | |
| (A + B) + Spec.obj B A M (M - D - 1) C (y - 1) hCpos ≤ | |
| (A + B) + mwf (Impl.Yn1 N M C D hN hM) C B A M (M - D - 1) hYpos hCpos := by | |
| nlinarith [hRecObj] | |
| exact le_trans hObjLe (le_trans hRecShift (le_max_right _ _)) | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: `Y>0 ∧ A≥0` の再帰式を与える。 | |
| 内容: 右端項と入替後 `mwf` の二項最大に分解。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 正傾き分岐の主定理。 | |
| -/ | |
| private 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 < Impl.Yn1 N M C D hN hM) (hAnonneg : A ≥ 0) : | |
| let YY := Impl.Yn1 N M C D hN hM | |
| let hCpos : 0 < C := | |
| Impl.Internal.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 | |
| simp only [Impl.Yn1, Impl.yOf, Spec.zfloorDiv, mwf, Spec.img, Spec.obj, Spec.dom] | |
| let YY : Int := Impl.Yn1 N M C D hN hM | |
| have hCpos : 0 < C := Impl.Internal.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) ∈ Spec.dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN), le_rfl⟩ | |
| have hobj := Spec.obj_le_mwf N M A B C D (N - 1) hN hM hxN1 | |
| have hobj_right : | |
| Spec.obj A B C D M (N - 1) hM = A * (N - 1) + B * Impl.Yn1 N M C D hN hM := by | |
| simp [Spec.obj, Spec.zfloorDiv, Impl.Yn1, Impl.yOf] | |
| simpa only [Impl.Yn1, Impl.yOf, Spec.zfloorDiv, mwf, Spec.img, Spec.obj, Spec.dom, ge_iff_le] | |
| using (hobj_right ▸ 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 | |
| simpa only [YY] using mwf_right_rec_le N M A B C D hN hM hC0 hD0 hCM hDM hYpos hCpos | |
| 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 | |
| simp only [Spec.img, Spec.obj, Spec.zfloorDiv, Spec.dom] | |
| refine Finset.max'_le | |
| (s := Spec.img N M A B C D hN hM) | |
| (H := Spec.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⟩ | |
| simpa only [YY] using | |
| obj_le_nonneg_max N M A B C D x hN hM hC0 hD0 hCM hDM hYpos hCpos hAnonneg hxDom | |
| 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` の最大に分解。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 負傾き分岐の主定理。 | |
| -/ | |
| private 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 < Impl.Yn1 N M C D hN hM) (hAneg : A < 0) : | |
| let YY := Impl.Yn1 N M C D hN hM | |
| let hCpos : 0 < C := | |
| Impl.Internal.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 | |
| simp only [Impl.Yn1, Impl.yOf, Spec.zfloorDiv, mwf, Spec.img, Spec.obj, Spec.dom] | |
| let YY : Int := Impl.Yn1 N M C D hN hM | |
| have hCpos : 0 < C := Impl.Internal.hCpos_of_Y_ge_one N M C D hN hM hC0 hD0 hDM hYpos | |
| have hZero_le : 0 ≤ mwf N M A B C D hN hM := by | |
| have hx0 : (0 : Int) ∈ Spec.dom N hN := by | |
| exact Finset.mem_Icc.mpr ⟨le_rfl, sub_nonneg.mpr ((Int.lt_iff_add_one_le).1 hN)⟩ | |
| have hobj0 := Spec.obj_le_mwf N M A B C D 0 hN hM hx0 | |
| simpa only [obj_zero_eq_zero A B C D M hM hD0 hDM] using 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 | |
| simpa only [YY] using mwf_left_rec_shift_le N M A B C D hN hM hC0 hD0 hCM hDM hYpos hCpos | |
| 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 | |
| simp only [Spec.img, Spec.obj, Spec.zfloorDiv, Spec.dom] | |
| refine Finset.max'_le | |
| (s := Spec.img N M A B C D hN hM) | |
| (H := Spec.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⟩ | |
| simpa only [YY] using | |
| obj_le_neg_max N M A B C D x hN hM hC0 hD0 hCM hDM hYpos hCpos hAneg hxDom | |
| 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` 形式へ移す。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 状態遷移定理列の入口。 | |
| -/ | |
| private theorem Mwf_step_init_equiv | |
| (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| let U := Impl.St.mk (B * Spec.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 | |
| simpa only [Impl.Internal.st_mwf, zero_add] using step_init_equiv N M A B C D hN hM | |
| /-- | |
| 入力/前提: 基底状態 `(n,m,a,b,c,d)=(1,1,0,0,0,0)`。 | |
| 主張: その `mwf` 値は `0`。 | |
| 内容: `Yn1 = 0` の閉形式を基底状態に適用した具体例。 | |
| 証明: `mwf_yn1_zero` と `Y_eq_zero_of_C_eq_zero` を使う。 | |
| 役割: `step_reduce_y0` 後の停止状態評価を 0 に潰す。 | |
| -/ | |
| private lemma mwf_one_one_zero : | |
| mwf 1 1 0 0 0 0 (by decide) (by decide) = 0 := by | |
| have hY0 : Impl.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] | |
| /-- | |
| 入力/前提: 正規化状態 `U` と `stnorm_y U ≠ 0`。 | |
| 主張: `stnorm_y U > 0`。 | |
| 内容: `stnorm_y` は常に非負なので、0 でなければ正。 | |
| 証明: `Y_nonneg` と `lt_of_le_of_ne` を使う。 | |
| 役割: `Mwf_step_reduce_equiv` や `step_fields_or_stop` で非停止枝の正性を得る。 | |
| -/ | |
| private lemma stnorm_y_pos_of_ne_zero (U : Impl.StNorm) (hy : Impl.Internal.stnorm_y U ≠ 0) : | |
| 0 < Impl.Internal.stnorm_y U := by | |
| exact lt_of_le_of_ne | |
| (Impl.Internal.Y_nonneg U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0) (fun h => hy h.symm) | |
| /-- | |
| 入力/前提: 正規化状態 `U` と `stnorm_y U > 0`。 | |
| 主張: `U.c > 0`。 | |
| 内容: 正規化後に高さが正なら Euclid 側第 2 成分も正である。 | |
| 証明: `hCpos_of_Y_ge_one` を `stnorm_y` 表現へ写して使う。 | |
| 役割: `mwf_yn1_pos_*` を `stnorm_mwf` に適用する前提を供給する。 | |
| -/ | |
| private lemma stnorm_c_pos_of_ypos (U : Impl.StNorm) | |
| (hYpos : 0 < Impl.Internal.stnorm_y U) : | |
| 0 < U.c := by | |
| exact Impl.Internal.hCpos_of_Y_ge_one U.n U.m U.c U.d U.hn U.hm U.hC0 U.hD0 U.hDM | |
| (by simpa only [Impl.Internal.stnorm_y] using hYpos) | |
| /-- | |
| 入力/前提: U : StNorm。 | |
| 主張: `step_reduce` 全体で評価式は不変。 | |
| 内容: `Y` と `A` の符号で分岐し枝定理を貼る。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: reduce 正しさの統合定理。 | |
| -/ | |
| private theorem Mwf_step_reduce_equiv | |
| (U : Impl.StNorm) : | |
| let V := Impl.Internal.step_reduce U | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = | |
| max V.r (V.s + Impl.Internal.st_mwf V) := by | |
| by_cases hY0 : Impl.Internal.stnorm_y U = 0 | |
| · have hbranch : | |
| let V := Impl.Internal.step_reduce_y0 U hY0 | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = | |
| max V.r (V.s + Impl.Internal.st_mwf V) := by | |
| have hLeft : | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) = | |
| max (max U.r U.s) (U.s + U.a * (U.n - 1)) := 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 | |
| calc | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = max U.r (U.s + max 0 (U.a * (U.n - 1))) := by | |
| simpa only [Impl.Internal.stnorm_mwf, mwf, Spec.img, Spec.obj, | |
| Spec.zfloorDiv, Spec.dom] using | |
| congrArg (fun t => max U.r (U.s + t)) hcore | |
| _ = max (max U.r U.s) (U.s + U.a * (U.n - 1)) := by | |
| simp only [add_max, add_zero, max_assoc] | |
| have hRight : | |
| max (Impl.Internal.step_reduce_y0 U hY0).r | |
| ((Impl.Internal.step_reduce_y0 U hY0).s + | |
| Impl.Internal.st_mwf (Impl.Internal.step_reduce_y0 U hY0)) = | |
| max (max U.r U.s) (U.s + U.a * (U.n - 1)) := by | |
| have hmwf0 : | |
| Impl.Internal.st_mwf (Impl.Internal.step_reduce_y0 U hY0) = 0 := by | |
| simp only [Impl.Internal.step_reduce_y0, Impl.Internal.st_mwf, mwf, Spec.img, | |
| Spec.obj, Spec.zfloorDiv, Spec.dom, Int.reduceSub] | |
| exact mwf_one_one_zero | |
| rw [hmwf0] | |
| simp only [Impl.Internal.step_reduce_y0, Int.max_assoc, max_self, add_zero] | |
| exact hLeft.trans hRight.symm | |
| simpa only [Impl.Internal.step_reduce, hY0, ↓reduceDIte, Impl.Internal.st_mwf] using | |
| hbranch | |
| · have hYpos : 0 < Impl.Internal.stnorm_y U := stnorm_y_pos_of_ne_zero U hY0 | |
| by_cases hAnonneg : 0 ≤ U.a | |
| · have hbranch : | |
| let V := Impl.Internal.step_reduce_ypos_a_nonneg U hYpos hAnonneg | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = | |
| max V.r (V.s + Impl.Internal.st_mwf V) := by | |
| calc | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = | |
| max | |
| (max U.r (U.s + (U.a * (U.n - 1) + U.b * Impl.Internal.stnorm_y U))) | |
| (U.s + | |
| mwf (Impl.Internal.stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos (stnorm_c_pos_of_ypos U hYpos)) := by | |
| rw [show Impl.Internal.stnorm_mwf U = | |
| max | |
| (U.a * (U.n - 1) + U.b * Impl.Internal.stnorm_y U) | |
| (mwf (Impl.Internal.stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos (stnorm_c_pos_of_ypos U hYpos)) by | |
| simpa only [Impl.Internal.stnorm_mwf, Impl.Internal.stnorm_y] using | |
| (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 [Impl.Internal.stnorm_y] using hYpos) hAnonneg)] | |
| rw [add_max, max_assoc] | |
| _ = max (Impl.Internal.step_reduce_ypos_a_nonneg U hYpos hAnonneg).r | |
| ((Impl.Internal.step_reduce_ypos_a_nonneg U hYpos hAnonneg).s + | |
| Impl.Internal.st_mwf | |
| (Impl.Internal.step_reduce_ypos_a_nonneg U hYpos hAnonneg)) := by | |
| rfl | |
| simpa only [Impl.Internal.step_reduce, hY0, ↓reduceDIte, hAnonneg, | |
| Impl.Internal.st_mwf] using hbranch | |
| · have hAneg : U.a < 0 := lt_of_not_ge hAnonneg | |
| have hbranch : | |
| let V := Impl.Internal.step_reduce_ypos_a_neg U hYpos hAneg | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = | |
| max V.r (V.s + Impl.Internal.st_mwf V) := by | |
| calc | |
| max U.r (U.s + Impl.Internal.stnorm_mwf U) | |
| = | |
| max | |
| (max U.r U.s) | |
| ((U.s + (U.a + U.b)) + | |
| mwf (Impl.Internal.stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos (stnorm_c_pos_of_ypos U hYpos)) := by | |
| rw [show Impl.Internal.stnorm_mwf U = | |
| max 0 | |
| ((U.a + U.b) + | |
| mwf (Impl.Internal.stnorm_y U) U.c U.b U.a U.m (U.m - U.d - 1) | |
| hYpos (stnorm_c_pos_of_ypos U hYpos)) by | |
| simpa only [Impl.Internal.stnorm_mwf, Impl.Internal.stnorm_y] using | |
| (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 [Impl.Internal.stnorm_y] using hYpos) hAneg)] | |
| rw [add_max] | |
| simp only [add_zero] | |
| rw [← max_assoc] | |
| simp only [add_assoc] | |
| _ = max (Impl.Internal.step_reduce_ypos_a_neg U hYpos hAneg).r | |
| ((Impl.Internal.step_reduce_ypos_a_neg U hYpos hAneg).s + | |
| Impl.Internal.st_mwf | |
| (Impl.Internal.step_reduce_ypos_a_neg U hYpos hAneg)) := by | |
| rfl | |
| simpa only [Impl.Internal.step_reduce, hY0, ↓reduceDIte, hAnonneg, | |
| Impl.Internal.st_mwf] using hbranch | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `step` 1回で評価式は不変。 | |
| 内容: normalize 同値と reduce 同値を合成。 | |
| 証明: 式変形・既存補題の書き換えで示す。 | |
| 役割: 反復アルゴリズム正しさの中核。 | |
| -/ | |
| private theorem mwf_step_equiv | |
| (U : Impl.St) : | |
| let V := Impl.Internal.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 | |
| let V := Impl.Internal.step_normalize U | |
| let W := Impl.Internal.step_reduce V | |
| have hnorm : | |
| 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 + Impl.Internal.stnorm_mwf V) := by | |
| simpa only [V, Impl.Internal.st_mwf, Impl.Internal.step_normalize, | |
| Impl.Internal.stnorm_mwf] using | |
| congrArg (fun t => max U.r t) (normalize_mwf_eq U.s U.n U.m U.a U.b U.c U.d U.hn U.hm) | |
| have hred : | |
| max V.r (V.s + Impl.Internal.stnorm_mwf V) = | |
| max W.r (W.s + Impl.Internal.st_mwf W) := by | |
| simpa only [V, W] using (Mwf_step_reduce_equiv V) | |
| simpa only [V, W, Impl.Internal.step, Impl.Internal.st_mwf] using hnorm.trans hred | |
| /-- | |
| 入力/前提: 状態 `U`。 | |
| 主張: `max U.r (U.s + st_mwf U)` は 1 ステップ後の同じ形と一致する。 | |
| 内容: `step` が保持する評価量を 1 行で取り出した補題。 | |
| 証明: `mwf_step_equiv` を `st_mwf` の形に言い換える。 | |
| 役割: `mwf_iter_aux_correct` で各分岐を共通化する。 | |
| -/ | |
| private lemma step_value_eq (U : Impl.St) : | |
| max U.r (U.s + Impl.Internal.st_mwf U) = | |
| max (Impl.Internal.step U).r | |
| ((Impl.Internal.step U).s + Impl.Internal.st_mwf (Impl.Internal.step U)) := by | |
| simpa only [Impl.Internal.st_mwf] using (mwf_step_equiv U) | |
| /-- | |
| 入力/前提: U : St、hc0 : U.c = 0。 | |
| 主張: `U.c=0` なら正規化後も `stnorm_y=0`。 | |
| 内容: `normC 0 = 0` と `Y_eq_zero_of_C_eq_zero` を適用。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 停止分岐への接続。 | |
| -/ | |
| private lemma stnorm_y_step_normalize_eq_zero | |
| (U : Impl.St) (hc0 : U.c = 0) : | |
| Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) = 0 := by | |
| have hCmod0 : U.c % U.m = 0 := by | |
| simpa only [hc0] using (Int.zero_emod U.m) | |
| simpa only [Impl.Internal.stnorm_y, Impl.Yn1, Impl.yOf, Spec.zfloorDiv, | |
| Impl.Internal.step_normalize, Impl.normS, Impl.normA, Impl.normC, Spec.zfloorMod, | |
| hCmod0, Impl.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) | |
| /-- | |
| 入力/前提: W : StNorm、h : stnorm_y W = 0。 | |
| 主張: 仮定 `stnorm_y=0` で `step_reduce` は `y0` 枝に一致。 | |
| 内容: 外側 `if` を仮定で簡約。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 停止証明で分岐を確定。 | |
| -/ | |
| private lemma step_reduce_eq_y0 | |
| (W : Impl.StNorm) (h : Impl.Internal.stnorm_y W = 0) : | |
| Impl.Internal.step_reduce W = Impl.Internal.step_reduce_y0 W h := by | |
| simp only [Impl.Internal.step_reduce, h, ↓reduceDIte] | |
| /-- | |
| 入力/前提: W : StNorm、hPos : 0 < stnorm_y W、hAnonneg : 0 ≤ W.a。 | |
| 主張: `stnorm_y>0 ∧ a≥0` で `step_reduce` は正傾き枝に一致。 | |
| 内容: 2段の `if` を仮定で簡約。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 縮小証明で分岐を確定。 | |
| -/ | |
| private lemma step_reduce_eq_ypos_a_nonneg | |
| (W : Impl.StNorm) (hPos : 0 < Impl.Internal.stnorm_y W) (hAnonneg : 0 ≤ W.a) : | |
| Impl.Internal.step_reduce W = Impl.Internal.step_reduce_ypos_a_nonneg W hPos hAnonneg := by | |
| simp only [Impl.Internal.step_reduce, ne_of_gt hPos, ↓reduceDIte, hAnonneg] | |
| /-- | |
| 入力/前提: W : StNorm、hPos : 0 < stnorm_y W、hAneg : W.a < 0。 | |
| 主張: `stnorm_y>0 ∧ a<0` で `step_reduce` は負傾き枝に一致。 | |
| 内容: 2段の `if` を仮定で簡約。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 縮小証明で分岐を確定。 | |
| -/ | |
| private lemma step_reduce_eq_ypos_a_neg | |
| (W : Impl.StNorm) (hPos : 0 < Impl.Internal.stnorm_y W) (hAneg : W.a < 0) : | |
| Impl.Internal.step_reduce W = Impl.Internal.step_reduce_ypos_a_neg W hPos hAneg := by | |
| unfold Impl.Internal.step_reduce | |
| have hnot : ¬ (0 ≤ W.a) := not_le.mpr hAneg | |
| simp only [ne_of_gt hPos, ↓reduceDIte, hnot] | |
| /-- | |
| 入力/前提: 状態 `U` と、正規化後の `stnorm_y = 0`。 | |
| 主張: そのとき `step U` の第2成分 `c` は `0`。 | |
| 内容: `step_reduce` の停止枝では `c := 0` である。 | |
| 証明: `step_reduce_eq_y0` に `congrArg Impl.St.c` を適用する。 | |
| 役割: 停止枝の `c` の読取りを共通化する。 | |
| -/ | |
| private lemma step_c_eq_zero_of_stnorm_y_eq_zero (U : Impl.St) | |
| (hY0 : Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) = 0) : | |
| (Impl.Internal.step U).c = 0 := by | |
| simpa only [Impl.Internal.step, hY0] using | |
| congrArg Impl.St.c (step_reduce_eq_y0 (Impl.Internal.step_normalize U) hY0) | |
| /-- | |
| 入力/前提: 状態 `U` と、正規化後の `stnorm_y` が 0 でないこと。 | |
| 主張: そのとき `step U` の第2成分 `c` は `U.m` に等しい。 | |
| 内容: `step_reduce` の非停止2分岐ではどちらも `c := m` である。 | |
| 証明: `step_normalize U` に対する `a` の符号分岐と `step_reduce_eq_ypos_*` を使う。 | |
| 役割: 停止判定から `stnorm_y` を逆算する補題や Euclid 接続補題を短くする。 | |
| -/ | |
| private lemma step_c_eq_m_of_stnorm_y_ne_zero (U : Impl.St) | |
| (hY0 : Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) ≠ 0) : | |
| (Impl.Internal.step U).c = U.m := by | |
| let W := Impl.Internal.step_normalize U | |
| have hPos : 0 < Impl.Internal.stnorm_y W := stnorm_y_pos_of_ne_zero W | |
| (by simpa only [W] using hY0) | |
| by_cases hAnonneg : 0 ≤ W.a | |
| · have hstep : Impl.Internal.step U = | |
| Impl.Internal.step_reduce_ypos_a_nonneg W hPos hAnonneg := by | |
| unfold Impl.Internal.step | |
| exact step_reduce_eq_ypos_a_nonneg W hPos hAnonneg | |
| simpa only [W, Impl.Internal.step_normalize] using congrArg Impl.St.c hstep | |
| · have hAneg : W.a < 0 := lt_of_not_ge hAnonneg | |
| have hstep : Impl.Internal.step U = Impl.Internal.step_reduce_ypos_a_neg W hPos hAneg := by | |
| unfold Impl.Internal.step | |
| exact step_reduce_eq_ypos_a_neg W hPos hAneg | |
| simpa only [W, Impl.Internal.step_normalize] using congrArg Impl.St.c hstep | |
| /-- | |
| 入力/前提: `U.c = 0`。 | |
| 主張: 1 ステップ後の tail 項 `max step.r (step.s + st_mwf step)` は `step.r` に潰れる。 | |
| 内容: 既に停止している状態では再帰側寄与が消える。 | |
| 証明: 正規化後の `y = 0` を使って `step_reduce_y0` に落とす。 | |
| 役割: `mwf_iter_aux_correct` の停止分岐を簡約する。 | |
| -/ | |
| private lemma step_tail_eq_of_c_zero | |
| (U : Impl.St) (hc0 : U.c = 0) : | |
| max (Impl.Internal.step U).r | |
| ((Impl.Internal.step U).s + Impl.Internal.st_mwf (Impl.Internal.step U)) = | |
| (Impl.Internal.step U).r := by | |
| have hY0 : Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) = 0 := | |
| stnorm_y_step_normalize_eq_zero U hc0 | |
| have hstep : | |
| Impl.Internal.step U = Impl.Internal.step_reduce_y0 (Impl.Internal.step_normalize U) hY0 := by | |
| unfold Impl.Internal.step | |
| exact step_reduce_eq_y0 (Impl.Internal.step_normalize U) hY0 | |
| have hmwf0 : | |
| Impl.Internal.st_mwf | |
| (Impl.Internal.step_reduce_y0 (Impl.Internal.step_normalize U) hY0) = 0 := by | |
| simpa only [Impl.Internal.step_reduce_y0, Impl.Internal.st_mwf, mwf, Spec.img, | |
| Spec.obj, Spec.zfloorDiv, Spec.dom, Int.reduceSub] using mwf_one_one_zero | |
| rw [hstep, hmwf0] | |
| simp [Impl.Internal.step_reduce_y0] | |
| /-- | |
| 入力/前提: `(step U).c = 0`。 | |
| 主張: 1 ステップ後の tail 項 `max step.r (step.s + st_mwf step)` は `step.r` に潰れる。 | |
| 内容: 次状態で停止する場合の共通簡約。 | |
| 証明: `step` の正規化後 `y = 0` を示して `step_reduce_y0` を適用する。 | |
| 役割: `mwf_iter_aux_correct` の再帰停止ケースを簡約する。 | |
| -/ | |
| private lemma step_tail_eq_of_step_c_zero | |
| (U : Impl.St) (hc0 : (Impl.Internal.step U).c = 0) : | |
| max (Impl.Internal.step U).r | |
| ((Impl.Internal.step U).s + Impl.Internal.st_mwf (Impl.Internal.step U)) = | |
| (Impl.Internal.step U).r := by | |
| have hY0 : Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) = 0 := by | |
| by_contra hYne | |
| exact (ne_of_gt U.hm) ((step_c_eq_m_of_stnorm_y_ne_zero U hYne).symm.trans hc0) | |
| have hstep : | |
| Impl.Internal.step U = Impl.Internal.step_reduce_y0 (Impl.Internal.step_normalize U) hY0 := by | |
| unfold Impl.Internal.step | |
| exact step_reduce_eq_y0 (Impl.Internal.step_normalize U) hY0 | |
| have hmwf0 : | |
| Impl.Internal.st_mwf | |
| (Impl.Internal.step_reduce_y0 (Impl.Internal.step_normalize U) hY0) = 0 := by | |
| simp only [Impl.Internal.step_reduce_y0, Impl.Internal.st_mwf, mwf, Spec.img, | |
| Spec.obj, Spec.zfloorDiv, Spec.dom, Int.reduceSub] | |
| exact mwf_one_one_zero | |
| rw [hstep, hmwf0] | |
| simp [Impl.Internal.step_reduce_y0] | |
| /-- | |
| 入力/前提: `U.c = 0`。 | |
| 主張: `mwf_iter_aux (k + 1) U = (step U).r`。 | |
| 内容: 既停止状態では 1 回分の fuel を与えても即座に答えが返る。 | |
| 証明: `mwf_iter_aux` の定義を `simp` で展開する。 | |
| 役割: `mwf_iter_aux_correct` の停止ケース整理に使う。 | |
| -/ | |
| private lemma mwf_iter_aux_succ_of_c_zero | |
| (k : Nat) (U : Impl.St) (hc0 : U.c = 0) : | |
| Impl.Internal.mwf_iter_aux (k + 1) U = (Impl.Internal.step U).r := by | |
| simp only [Impl.Internal.mwf_iter_aux, hc0, ↓reduceDIte] | |
| /-- | |
| 入力/前提: `U.c = 0` と正の fuel `k + 1`。 | |
| 主張: `mwf_iter_aux` は評価量 `max U.r (U.s + st_mwf U)` を返す。 | |
| 内容: 停止状態では `mwf_iter_aux` が直ちに `(step U).r` を返し、それが保存量に一致する。 | |
| 証明: `mwf_iter_aux_succ_of_c_zero` の値と `step_value_eq`, `step_tail_eq_of_c_zero` をつなぐ。 | |
| 役割: `mwf_iter_aux_correct` の停止枝を共通化する。 | |
| -/ | |
| private lemma mwf_iter_aux_value_of_c_zero | |
| (k : Nat) (U : Impl.St) (hc0 : U.c = 0) : | |
| Impl.Internal.mwf_iter_aux (k + 1) U = max U.r (U.s + Impl.Internal.st_mwf U) := by | |
| calc | |
| Impl.Internal.mwf_iter_aux (k + 1) U = (Impl.Internal.step U).r := | |
| mwf_iter_aux_succ_of_c_zero k U hc0 | |
| _ = max U.r (U.s + Impl.Internal.st_mwf U) := | |
| ((step_value_eq U).trans (step_tail_eq_of_c_zero U hc0)).symm | |
| /-- | |
| 入力/前提: `U.c ≠ 0` と、`step U` 側での `mwf_iter_aux` の正しさ。 | |
| 主張: 元の状態でも 1 回進めた fuel で同じ保存量を返す。 | |
| 内容: 非停止枝では `mwf_iter_aux` は `step U` へ進み、値は `step_value_eq` で戻せる。 | |
| 証明: 定義を `simp` 展開して `step U` 側の仮定と `step_value_eq` を連結する。 | |
| 役割: `mwf_iter_aux_correct` の非停止枝を base/succ で共通化する。 | |
| -/ | |
| private lemma mwf_iter_aux_step_correct_of_c_ne | |
| (k : Nat) (U : Impl.St) (hc : U.c ≠ 0) | |
| (hstep : | |
| Impl.Internal.mwf_iter_aux k (Impl.Internal.step U) = | |
| max (Impl.Internal.step U).r | |
| ((Impl.Internal.step U).s + Impl.Internal.st_mwf (Impl.Internal.step U))) : | |
| Impl.Internal.mwf_iter_aux (k + 1) U = max U.r (U.s + Impl.Internal.st_mwf U) := by | |
| calc | |
| Impl.Internal.mwf_iter_aux (k + 1) U = Impl.Internal.mwf_iter_aux k (Impl.Internal.step U) := by | |
| simp only [Impl.Internal.mwf_iter_aux, hc, ↓reduceDIte] | |
| _ = max (Impl.Internal.step U).r | |
| ((Impl.Internal.step U).s + Impl.Internal.st_mwf (Impl.Internal.step U)) := hstep | |
| _ = max U.r (U.s + Impl.Internal.st_mwf U) := (step_value_eq U).symm | |
| /-- | |
| 入力/前提: U : St、hc0 : U.c = 0。 | |
| 主張: `U.c = 0` なら 1 ステップ後も `(step U).c = 0`。 | |
| 内容: `stnorm_y=0` の枝へ簡約し `step_reduce_y0` の定義から従う。 | |
| 証明: 式変形で示す。 | |
| 役割: 停止条件の不変性。 | |
| -/ | |
| private lemma step_c_zero_of_c_zero (U : Impl.St) (hc0 : U.c = 0) : | |
| (Impl.Internal.step U).c = 0 := by | |
| have hY0 : Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) = 0 := | |
| stnorm_y_step_normalize_eq_zero U hc0 | |
| exact step_c_eq_zero_of_stnorm_y_eq_zero U hY0 | |
| /-- | |
| 入力/前提: `U : St`。 | |
| 主張: `step U` は停止枝か、Euclid 形更新 | |
| `((step U).c, (step U).m) = (U.m, U.c % U.m)` のどちらかである。 | |
| 内容: `step_reduce` の3分岐を一度だけ展開し、`c` と `m` の更新式を同時に読む。 | |
| 証明: `step_normalize U` に対する `stnorm_y` と `a` の場合分け。 | |
| 役割: `step_c_or`, `step_after_preprocess_euclid`, 進捗補題の共通核。 | |
| -/ | |
| private lemma step_fields_or_stop (U : Impl.St) : | |
| (Impl.Internal.step U).c = 0 ∨ | |
| ((Impl.Internal.step U).c = U.m ∧ (Impl.Internal.step U).m = U.c % U.m) := by | |
| let W := Impl.Internal.step_normalize U | |
| by_cases hy0 : Impl.Internal.stnorm_y W = 0 | |
| · left | |
| exact step_c_eq_zero_of_stnorm_y_eq_zero U (by simpa only [W] using hy0) | |
| · right | |
| have hPos : 0 < Impl.Internal.stnorm_y W := stnorm_y_pos_of_ne_zero W | |
| (by simpa only [W] using hy0) | |
| by_cases hAnonneg : 0 ≤ W.a | |
| · have hstep : Impl.Internal.step U = | |
| Impl.Internal.step_reduce_ypos_a_nonneg W hPos hAnonneg := by | |
| unfold Impl.Internal.step | |
| exact step_reduce_eq_ypos_a_nonneg W hPos hAnonneg | |
| refine ⟨?_, ?_⟩ | |
| · simpa only [W, Impl.Internal.step_normalize] using congrArg Impl.St.c hstep | |
| · simpa only [W, Impl.Internal.step_normalize] using congrArg Impl.St.m hstep | |
| · have hAneg : W.a < 0 := lt_of_not_ge hAnonneg | |
| have hstep : Impl.Internal.step U = | |
| Impl.Internal.step_reduce_ypos_a_neg W hPos hAneg := by | |
| unfold Impl.Internal.step | |
| exact step_reduce_eq_ypos_a_neg W hPos hAneg | |
| refine ⟨?_, ?_⟩ | |
| · simpa only [W, Impl.Internal.step_normalize] using congrArg Impl.St.c hstep | |
| · simpa only [W, Impl.Internal.step_normalize] using congrArg Impl.St.m hstep | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: `(step U).c = 0` または `(step U).c = U.m`。 | |
| 内容: `step_fields_or_stop` から `c` 成分だけを取り出す。 | |
| 証明: 場合分けで直ちに従う。 | |
| 役割: Euclid 形更新の片方成分を特定する。 | |
| -/ | |
| private lemma step_c_or (U : Impl.St) : (Impl.Internal.step U).c = 0 ∨ | |
| (Impl.Internal.step U).c = U.m := by | |
| rcases step_fields_or_stop U with hc0 | ⟨hc, _⟩ | |
| · exact Or.inl hc0 | |
| · exact Or.inr hc | |
| /-- | |
| 入力/前提: U : St。 | |
| 主張: 1ステップで `m` が減るか `c=0` になる。 | |
| 内容: `step_reduce` の3分岐を場合分け。 | |
| 証明: 場合分け・式変形で示す。 | |
| 役割: 反復の進捗・停止保証。 | |
| -/ | |
| private theorem mwf_step_reduce_reduction | |
| (U : Impl.St) : U.m > (Impl.Internal.step U).m ∨ (Impl.Internal.step U).c = 0 := by | |
| cases step_fields_or_stop U with | |
| | inl hc0 => exact Or.inr hc0 | |
| | inr hfields => | |
| left | |
| have hlt : (Impl.Internal.step U).m < U.m := by | |
| calc | |
| (Impl.Internal.step U).m = U.c % U.m := hfields.2 | |
| _ < U.m := Int.emod_lt_of_pos U.c U.hm | |
| exact hlt | |
| /-- | |
| 入力/前提: `U : St`、`h : (step (step U)).c ≠ 0`。 | |
| 主張: 前処理 1 ステップ後、次のステップが停止しなければ Euclid 1 ステップに一致。 | |
| 内容: `step_fields_or_stop` を `step U` に適用し停止分岐を排除する。 | |
| 証明: 場合分けで示す。 | |
| 役割: Euclid 反復解析のための橋渡し。 | |
| -/ | |
| private lemma step_after_preprocess_euclid (U : Impl.St) | |
| (h : (Impl.Internal.step (Impl.Internal.step U)).c ≠ 0) : | |
| (Impl.Internal.step (Impl.Internal.step U)).c = (Impl.Internal.step U).m ∧ | |
| (Impl.Internal.step (Impl.Internal.step U)).m = | |
| (Impl.Internal.step U).c % (Impl.Internal.step U).m := by | |
| exact (step_fields_or_stop (Impl.Internal.step U)).resolve_left h | |
| end Internal | |
| namespace Fuel | |
| namespace Internal | |
| end Internal | |
| end Fuel | |
| namespace Fuel | |
| namespace Internal | |
| /-- | |
| 目的: `step` を `k` 回適用した状態 `stepN k U` を定義する。 | |
| 定義: `k=0` で恒等、`k+1` で `step` を 1 回進めて再帰。 | |
| 入力/前提: `k : Nat`、`U : St`。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 反復回数の解析基盤。 | |
| -/ | |
| private def stepN : Nat → Impl.St → Impl.St | |
| | 0, U => U | |
| | k + 1, U => stepN k (Impl.Internal.step U) | |
| /-- | |
| 入力/前提: `k : Nat`, `U : St`。 | |
| 主張: `stepN (k+1) U = stepN k (step U)`。 | |
| 内容: `stepN` の再帰定義の 1 ステップ展開。 | |
| 証明: 定義より自明。 | |
| 役割: `stepN_eq_euclidN` や `stepN_stay_from_succ` の `succ` ケース簡約に使う。 | |
| -/ | |
| private lemma stepN_succ (k : Nat) (U : Impl.St) : | |
| stepN (k + 1) U = stepN k (Impl.Internal.step U) := by | |
| rfl | |
| /-- | |
| 入力/前提: t : Nat、V : St、h : V.c = 0。 | |
| 主張: `V.c = 0` なら任意回数の `stepN` でも `c=0`。 | |
| 内容: `t` による帰納法で `step_c_zero_of_c_zero` を用いる。 | |
| 証明: 帰納法・既存補題の書き換えで示す。 | |
| 役割: 停止条件の不変性。 | |
| -/ | |
| private lemma stepN_c_zero_of_c_zero (t : Nat) (V : Impl.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 : (Impl.Internal.step V).c = 0 := Mwf.Internal.step_c_zero_of_c_zero V h | |
| simpa only [stepN, Impl.Internal.step, Impl.Internal.step_reduce, Impl.Internal.stnorm_y, | |
| Impl.Yn1, Impl.yOf, Spec.zfloorDiv, Impl.Internal.step_normalize, Impl.normS, Impl.normA, | |
| Impl.normC, Spec.zfloorMod, Impl.normD, Impl.Internal.step_reduce_y0, Int.max_assoc, | |
| Impl.Internal.step_reduce_ypos_a_nonneg, Impl.Internal.step_reduce_ypos_a_neg, dite_eq_ite] | |
| using (ih (Impl.Internal.step V) hstep) | |
| /-- | |
| 目的: Nat 版 Euclid 1 ステップ `euclid_step` を定義する。 | |
| 定義: `m=0` なら `(c,0)` に据え置き、そうでなければ `(m, c % m)`。 | |
| 入力/前提: c m : Nat。 | |
| 出力: 型 `Nat × Nat` の値を返す。 | |
| 役割: Euclid 反復の基本操作。 | |
| -/ | |
| private 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` と対応付ける対象。 | |
| -/ | |
| private 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 | |
| end Internal | |
| /-- | |
| 目的: Euclid 反復 API 用に `euclidN` を `Mwf.Fuel` 配下へ再公開する。 | |
| 定義: `Mwf.Fuel.Internal.euclidN` への薄い別名。 | |
| 入力/前提: `k c m : Nat`。 | |
| 出力: 型 `Nat × Nat` の値を返す。 | |
| 役割: 停止時刻 `euclidTau` と公開停止補題の型に現れる Euclid 反復を `Mwf.Fuel` に集約する。 | |
| -/ | |
| abbrev euclidN : Nat → Nat → Nat → Nat × Nat := Internal.euclidN | |
| namespace Internal | |
| /-- | |
| 入力/前提: c m : Nat。 | |
| 主張: `euclidN 0 c m = (c, m)`。 | |
| 内容: 定義の簡約(`rfl`)。 | |
| 証明: 定義展開で示す。 | |
| 役割: 再帰の基底簡約。 | |
| -/ | |
| @[simp] private 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 回適用した後の再帰形。 | |
| 証明: 既存補題の適用と式変形で示す。 | |
| 役割: 再帰展開用の補助。 | |
| -/ | |
| private 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` の対応付けに使う。 | |
| -/ | |
| private def stPairNat (U : Impl.St) : Nat × Nat := (Int.toNat U.c, Int.toNat U.m) | |
| /-- | |
| 入力/前提: `z : Int`、`hz : 0 < z`。 | |
| 主張: `Int.toNat z ≠ 0`。 | |
| 内容: `Int.toNat z = 0` なら `z ≤ 0` と矛盾する。 | |
| 証明: `Int.toNat_eq_zero` に帰着する。 | |
| 役割: `step_after_preprocess_euclid_nat` や Euclid 非停止性の証明で | |
| `Int` の正性から `Nat` 側の非零性を取り出す補助。 | |
| -/ | |
| private lemma int_toNat_ne_zero_of_pos {z : Int} (hz : 0 < z) : Int.toNat z ≠ 0 := by | |
| intro hz0 | |
| exact (not_le_of_gt hz) ((Int.toNat_eq_zero).1 hz0) | |
| /-- | |
| 入力/前提: `a b : Int`、`0 ≤ a`、`0 < b`。 | |
| 主張: 整数剰余を `Int.toNat` へ落とすと自然数の `%` に一致する。 | |
| 内容: `Int.natCast_toNat_eq_self` と `Int.natCast_mod` による単純な移送。 | |
| 証明: 両辺を `Int` に持ち上げて `rw` で示す。 | |
| 役割: `step_after_preprocess_euclid_nat` で Euclid 更新の第2成分を `Nat` 側へ移す。 | |
| -/ | |
| private lemma int_toNat_emod_of_nonneg (a b : Int) (ha : 0 ≤ a) (hb : 0 < b) : | |
| Int.toNat (a % b) = Int.toNat a % Int.toNat b := by | |
| apply Int.ofNat.inj | |
| calc | |
| (Int.toNat (a % b) : Int) = a % b := by | |
| exact Int.toNat_of_nonneg (Int.emod_nonneg _ (ne_of_gt hb)) | |
| _ = ((Int.toNat a : Nat) : Int) % ((Int.toNat b : Nat) : Int) := by | |
| rw [Int.natCast_toNat_eq_self.mpr ha, Int.natCast_toNat_eq_self.mpr (le_of_lt hb)] | |
| _ = ((Int.toNat a % Int.toNat b : Nat) : Int) := by | |
| rw [Int.natCast_mod] | |
| /-- | |
| 入力/前提: 状態 `U : St`。 | |
| 主張: `(step U).c` は非負。 | |
| 内容: `step` 後の `c` は `0` か `U.m`。 | |
| 証明: `step_c_or` の場合分け。 | |
| 役割: `Int` の剰余を `Nat` に落とす補題の前提を供給する。 | |
| -/ | |
| private lemma step_c_nonneg (U : Impl.St) : 0 ≤ (Impl.Internal.step U).c := by | |
| cases Mwf.Internal.step_c_or U with | |
| | inl h0 => | |
| simp only [h0, le_refl] | |
| | inr h1 => | |
| simpa only [h1] using (le_of_lt U.hm) | |
| /-- | |
| 入力/前提: `U : Impl.St`、`h : (Impl.Internal.step (Impl.Internal.step U)).c ≠ 0`。 | |
| 主張: `Impl.Internal.step` の 1 ステップが Euclid 更新に一致する(Nat 版)。 | |
| 内容: `step_after_preprocess_euclid` を `Int.toNat` と `%` の移送補題へ流す。 | |
| 証明: `ext` して `simp` と helper の書換えで示す。 | |
| 役割: `stepN_eq_euclidN` の橋渡し。 | |
| -/ | |
| private lemma step_after_preprocess_euclid_nat (U : Impl.St) | |
| (h : (Impl.Internal.step (Impl.Internal.step U)).c ≠ 0) : | |
| stPairNat (Impl.Internal.step (Impl.Internal.step U)) = | |
| euclid_step (stPairNat (Impl.Internal.step U)).1 (stPairNat (Impl.Internal.step U)).2 := by | |
| rcases Mwf.Internal.step_after_preprocess_euclid U h with ⟨hc, hm⟩ | |
| have hm_nat_ne : (Int.toNat (Impl.Internal.step U).m) ≠ 0 := | |
| int_toNat_ne_zero_of_pos (Impl.Internal.step U).hm | |
| have hmod : | |
| Int.toNat ((Impl.Internal.step U).c % (Impl.Internal.step U).m) = | |
| (Int.toNat (Impl.Internal.step U).c) % (Int.toNat (Impl.Internal.step U).m) := by | |
| exact int_toNat_emod_of_nonneg | |
| (Impl.Internal.step U).c (Impl.Internal.step U).m (step_c_nonneg U) (Impl.Internal.step U).hm | |
| ext <;> simp only [euclid_step, stPairNat, hm_nat_ne, ↓reduceDIte, hc, hm, hmod] | |
| /-- | |
| 入力/前提: `U : St`、`t : Nat`、`hStay : ∀ i, i ≤ t → (stepN i (step U)).c ≠ 0`。 | |
| 主張: `c ≠ 0` の間、`stepN` と `euclidN` の反復が一致する。 | |
| 内容: `step U` を初期状態とし、`t` 回の反復一致を帰納法で示す。 | |
| 証明: 帰納法・既存補題の書き換えで示す。 | |
| 役割: Euclid 反復による停止上界評価に使う。 | |
| -/ | |
| private lemma stepN_eq_euclidN (U : Impl.St) (t : Nat) | |
| (hStay : ∀ i, i ≤ t → (stepN i (Impl.Internal.step U)).c ≠ 0) : | |
| stPairNat (stepN t (Impl.Internal.step U)) = | |
| euclidN t (stPairNat (Impl.Internal.step U)).1 (stPairNat (Impl.Internal.step U)).2 := by | |
| induction t generalizing U with | |
| | zero => | |
| simp only [stepN, euclidN] | |
| | succ t ih => | |
| have h1 : (Impl.Internal.step (Impl.Internal.step U)).c ≠ 0 := by | |
| have h1' : (1 : Nat) ≤ t + 1 := Nat.succ_le_succ (Nat.zero_le _) | |
| simpa only [stepN_succ, stepN, ne_eq] using hStay 1 h1' | |
| have hstep : | |
| stPairNat (Impl.Internal.step (Impl.Internal.step U)) = | |
| euclid_step (stPairNat (Impl.Internal.step U)).1 (stPairNat (Impl.Internal.step U)).2 := | |
| step_after_preprocess_euclid_nat U h1 | |
| have hStay' : ∀ i, i ≤ t → (stepN i (Impl.Internal.step (Impl.Internal.step U))).c ≠ 0 := by | |
| intro i hi | |
| have hi' : i + 1 ≤ t + 1 := Nat.succ_le_succ hi | |
| simpa only [stepN_succ, ne_eq] using hStay (i + 1) hi' | |
| have ih' : | |
| stPairNat (stepN t (Impl.Internal.step (Impl.Internal.step U))) = | |
| euclidN t (stPairNat (Impl.Internal.step (Impl.Internal.step U))).1 | |
| (stPairNat (Impl.Internal.step (Impl.Internal.step U))).2 := | |
| ih (U := Impl.Internal.step U) hStay' | |
| let p := euclid_step (stPairNat (Impl.Internal.step U)).1 (stPairNat (Impl.Internal.step U)).2 | |
| have ih'' : | |
| stPairNat (stepN t (Impl.Internal.step (Impl.Internal.step U))) = | |
| euclidN t p.1 p.2 := by | |
| simpa only [p, hstep] using ih' | |
| simpa only [stepN_succ, 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` の前提を作る補助。 | |
| -/ | |
| private lemma stepN_stay_from_succ (U : Impl.St) (k : Nat) | |
| (hStay : ∀ i, i ≤ k + 1 → (stepN i U).c ≠ 0) : | |
| ∀ i, i ≤ k → (stepN i (Impl.Internal.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 [stepN_succ, ne_eq] using h | |
| /-- | |
| 入力/前提: i j : Nat、U : St。 | |
| 主張: `stepN (i + j) U = stepN j (stepN i U)`。 | |
| 内容: `i` による帰納法で `stepN` の再帰を展開する。 | |
| 証明: 帰納法で示す。 | |
| 役割: 反復の分割・再結合に使う。 | |
| -/ | |
| private lemma stepN_add (i j : Nat) (U : Impl.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, Impl.Internal.step, | |
| Impl.Internal.step_reduce, Impl.Internal.stnorm_y, Impl.Yn1, Impl.yOf, Spec.zfloorDiv, | |
| Impl.Internal.step_normalize, Impl.normS, Impl.normA, Impl.normC, Spec.zfloorMod, | |
| Impl.normD, Impl.Internal.step_reduce_y0, Int.max_assoc, | |
| Impl.Internal.step_reduce_ypos_a_nonneg, Impl.Internal.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` を用いた反証法。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 途中段階の非停止性を引き継ぐ補助。 | |
| -/ | |
| private lemma stepN_nonzero_of_le (U : Impl.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 | |
| /-- | |
| 入力/前提: 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 反復の分割・再結合に使う。 | |
| -/ | |
| private 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 反復の停止不変性。 | |
| -/ | |
| private 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 i j : Nat`、`i ≤ j`、`i` 時刻で第2成分が 0。 | |
| 主張: `j` 時刻でも第2成分は 0。 | |
| 内容: `euclidN_add` で後半の反復に分解し、0 から始まる tail は | |
| `euclidN_c_zero_of_c_zero` で消える。 | |
| 証明: 反復分解と既存補題の書き換えで示す。 | |
| 役割: `euclidN_nonzero_of_le` および停止性の単調性に使う。 | |
| -/ | |
| private lemma euclidN_c_zero_mono (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 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 反復の非停止性を引き継ぐ補助。 | |
| -/ | |
| private 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 | |
| exact mt (euclidN_c_zero_mono c m i k hi) hk | |
| /-- | |
| 入力/前提: `fib (k+3) ≤ a`, `fib (k+2) ≤ b`。 | |
| 主張: `fib (k+4) ≤ a + b`。 | |
| 内容: Fibonacci の漸化式を上界評価に持ち上げる補題。 | |
| 証明: `fib_add_two` を展開して両辺を足し合わせる。 | |
| 役割: Euclid 反復の 2 段分下界を 1 つ先へ進める。 | |
| -/ | |
| private lemma fib_add_two_le_of_bounds (k a b : Nat) | |
| (ha : Nat.fib (k + 3) ≤ a) (hb : Nat.fib (k + 2) ≤ b) : | |
| Nat.fib (k + 4) ≤ a + b := by | |
| calc | |
| Nat.fib (k + 4) = Nat.fib (k + 3) + Nat.fib (k + 2) := by | |
| simpa only [Nat.add_assoc, Nat.add_comm, Nat.add_left_comm, Nat.reduceAdd] using | |
| (Nat.fib_add_two (n := k + 2)) | |
| _ ≤ a + b := Nat.add_le_add ha hb | |
| /-- | |
| 入力/前提: `m > 0` かつ `m ≤ n`。 | |
| 主張: `m + n % m ≤ n`。 | |
| 内容: 商 `n / m` が少なくとも 1 であることから、余りつき分解の主項が `m` を吸収する。 | |
| 証明: `n % m + m * (n / m) = n` と `1 ≤ n / m` を組み合わせる。 | |
| 役割: Euclid 反復で現れる `r + n % r` 型の上界評価を共通化する。 | |
| -/ | |
| private lemma add_mod_le_self_of_le (n m : Nat) (hm_pos : 0 < m) (hm_le : m ≤ n) : | |
| m + n % m ≤ n := by | |
| have hq_ge : 1 ≤ n / m := Nat.succ_le_of_lt (Nat.div_pos hm_le hm_pos) | |
| have hmul_ge : m ≤ m * (n / m) := by | |
| calc | |
| m = m * 1 := by simp | |
| _ ≤ m * (n / m) := Nat.mul_le_mul_left m hq_ge | |
| have hsum_le : m + n % m ≤ m * (n / m) + n % m := | |
| Nat.add_le_add_right hmul_ge (n % m) | |
| exact hsum_le.trans_eq (by simpa only [Nat.add_comm] using (Nat.mod_add_div n m)) | |
| /-- | |
| 入力/前提: `m ≠ 0` と、`euclidN i c m` が `k+1` 回まで停止しないこと。 | |
| 主張: 1 回 Euclid 更新した `(m, c % m)` から見ても、`k` 回までは停止しない。 | |
| 内容: `euclidN_succ` を 1 回展開し、停止しないという仮定を tail 側へ移す。 | |
| 証明: `i+1` 時刻の非停止性を `simpa` で書き換える。 | |
| 役割: `euclidN_fib_lower` 系で繰り返し現れる tail への移送を共通化する。 | |
| -/ | |
| private lemma euclidN_stay_tail (c m k : Nat) (hm : m ≠ 0) | |
| (hStay : ∀ i, i ≤ k + 1 → (Fuel.euclidN i c m).2 ≠ 0) : | |
| ∀ i, i ≤ k → (Fuel.euclidN i m (c % m)).2 ≠ 0 := by | |
| intro i hi | |
| have h := hStay (i + 1) (Nat.succ_le_succ hi) | |
| simpa only [euclidN_succ, euclid_step, hm, ↓reduceDIte] using h | |
| /-- | |
| 入力/前提: `m ≠ 0` と `c % m ≠ 0`。 | |
| 主張: `fib 3 ≤ m`。 | |
| 内容: 非零剰余は `0 < c % m < m` を満たすので `m ≥ 2`。 | |
| 証明: `Nat.mod_lt` と剰余の正性から `2 ≤ m` を示す。 | |
| 役割: `euclidN_fib_lower` の `k = 1` 枝を短くする。 | |
| -/ | |
| private lemma fib_three_le_of_mod_ne_zero (c m : Nat) (hm : m ≠ 0) (hmod : c % m ≠ 0) : | |
| Nat.fib 3 ≤ m := by | |
| have hm_pos : 0 < m := Nat.pos_of_ne_zero hm | |
| have hmod_pos : 0 < c % m := Nat.pos_of_ne_zero hmod | |
| have hmod_lt : c % m < m := Nat.mod_lt c hm_pos | |
| have h1lt : 1 < m := lt_of_le_of_lt (Nat.succ_le_of_lt hmod_pos) hmod_lt | |
| simpa using Nat.succ_le_of_lt h1lt | |
| /-- | |
| 入力/前提: `m ≠ 0`、`c % m ≠ 0`、および `(c % m, m % (c % m))` の Fibonacci 下界。 | |
| 主張: `fib (k + 4) ≤ m`。 | |
| 内容: `fib (k + 4) ≤ c % m + m % (c % m)` を作り、`r + m % r ≤ m` で上から抑える。 | |
| 証明: `fib_add_two_le_of_bounds` と `add_mod_le_self_of_le` を合成する。 | |
| 役割: `euclidN_fib_lower` の 2 段目以降の算術部分を共通化する。 | |
| -/ | |
| private lemma fib_four_le_of_mod_bounds (c m k : Nat) (hm : m ≠ 0) (hmod : c % m ≠ 0) | |
| (hmod1 : Nat.fib (k + 3) ≤ c % m) (hmod2 : Nat.fib (k + 2) ≤ m % (c % m)) : | |
| Nat.fib (k + 4) ≤ m := by | |
| have hm_pos : 0 < m := Nat.pos_of_ne_zero hm | |
| have hmod_pos : 0 < c % m := Nat.pos_of_ne_zero hmod | |
| have hmod_le : c % m ≤ m := Nat.le_of_lt (Nat.mod_lt c hm_pos) | |
| have hsum_le : c % m + m % (c % m) ≤ m := by | |
| exact add_mod_le_self_of_le m (c % m) hmod_pos hmod_le | |
| exact (fib_add_two_le_of_bounds k (c % m) (m % (c % m)) hmod1 hmod2).trans hsum_le | |
| /-- | |
| 入力/前提: `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` の反証に使う。 | |
| -/ | |
| private lemma euclidN_fib_lower (c m k : Nat) | |
| (hStay : ∀ i, i ≤ k → (Fuel.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_pos : 0 < m := Nat.pos_of_ne_zero (hStay 0 (Nat.zero_le _)) | |
| simpa using Nat.succ_le_of_lt hm_pos | |
| | succ k0 => | |
| have hm0 : m ≠ 0 := hStay 0 (Nat.zero_le _) | |
| set r1 : Nat := c % m | |
| have hStay1 : ∀ i, i ≤ k0 → (Fuel.euclidN i m r1).2 ≠ 0 := by | |
| simpa only [r1] using euclidN_stay_tail c m k0 hm0 hStay | |
| have hr1_ne : r1 ≠ 0 := by | |
| simpa only [euclidN_zero, r1] using hStay1 0 (Nat.zero_le _) | |
| have hr1_lower : Nat.fib (k0 + 2) ≤ r1 := | |
| ih k0 (Nat.lt_succ_self k0) m r1 hStay1 | |
| cases k0 with | |
| | zero => | |
| simpa only [r1] using fib_three_le_of_mod_ne_zero c m hm0 hr1_ne | |
| | succ k1 => | |
| set r2 : Nat := m % r1 | |
| have hStay2 : ∀ i, i ≤ k1 → (Fuel.euclidN i r1 r2).2 ≠ 0 := by | |
| simpa only [r1, r2] using euclidN_stay_tail m r1 k1 hr1_ne hStay1 | |
| have hr2_lower : Nat.fib (k1 + 2) ≤ r2 := | |
| ih k1 (Nat.lt_succ_of_lt (Nat.lt_succ_self k1)) r1 r2 hStay2 | |
| simpa only [r1, r2] using | |
| fib_four_le_of_mod_bounds c m k1 hm0 hr1_ne hr1_lower hr2_lower | |
| /-- | |
| 入力/前提: `m > 0` かつ `m < c`。 | |
| 主張: `fib 3 ≤ c`。 | |
| 内容: `m ≥ 1` から `c ≥ 2` を得て、`fib 3 = 2` を代入する。 | |
| 証明: `Nat.succ_le_of_lt` と `lt_of_le_of_lt` をつなぐ。 | |
| 役割: `euclidN_fib_lower_first_of_lt` の基底ケースを短くする。 | |
| -/ | |
| private lemma fib_three_le_of_lt {c m : Nat} (hm : 0 < m) (hcm : m < c) : Nat.fib 3 ≤ c := by | |
| have h1_le_m : 1 ≤ m := Nat.succ_le_of_lt hm | |
| 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 | |
| simpa using h2_le_c | |
| /-- | |
| 入力/前提: `euclidN` が `k+1` 回まで停止しない。 | |
| 主張: 初期第2成分 `m` は `fib (k+3)` 以上。 | |
| 内容: `euclidN_fib_lower` の `Nat.succ k` 版を添字だけ整える。 | |
| 証明: 既存補題の `simpa`。 | |
| 役割: `euclidN_fib_lower_first_of_lt` の succ ケース前半を短くする。 | |
| -/ | |
| private lemma euclidN_fib_lower_succ (c m k : Nat) | |
| (hStay : ∀ i, i ≤ k + 1 → (Fuel.euclidN i c m).2 ≠ 0) : | |
| Nat.fib (k + 3) ≤ m := by | |
| simpa only [Nat.succ_eq_add_one, Nat.add_assoc, Nat.add_comm, Nat.add_left_comm] using | |
| (euclidN_fib_lower c m (Nat.succ k) hStay) | |
| /-- | |
| 入力/前提: `m > 0`, `m < c`, および `m` と `c % m` への Fibonacci 下界。 | |
| 主張: `fib (k + 4) ≤ c`。 | |
| 内容: `fib (k + 4) ≤ m + c % m` を作り、`m + c % m ≤ c` で押さえる。 | |
| 証明: `fib_add_two_le_of_bounds` と `add_mod_le_self_of_le` の合成。 | |
| 役割: `euclidN_fib_lower_first_of_lt` の succ ケース終盤を共通化する。 | |
| -/ | |
| private lemma fib_four_le_of_lt_and_mod (c m k : Nat) (hm_pos : 0 < m) (hcm : m < c) | |
| (hm_lower : Nat.fib (k + 3) ≤ m) (hmod_lower : Nat.fib (k + 2) ≤ c % m) : | |
| Nat.fib (k + 4) ≤ c := by | |
| exact (fib_add_two_le_of_bounds k m (c % m) hm_lower hmod_lower).trans | |
| (add_mod_le_self_of_le c m hm_pos (Nat.le_of_lt hcm)) | |
| /-- | |
| 入力/前提: `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` 側停止上界を示すための強化補題。 | |
| -/ | |
| private 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 => | |
| exact fib_three_le_of_lt (Nat.pos_of_ne_zero (hStay 0 (Nat.zero_le _))) hcm | |
| | 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 | |
| simpa only [r1] using euclidN_stay_tail c m k0 hm_ne hStay | |
| have hm_lower : Nat.fib (k0 + 3) ≤ m := euclidN_fib_lower_succ c m k0 hStay | |
| have hr1_lower : Nat.fib (k0 + 2) ≤ r1 := | |
| euclidN_fib_lower m r1 k0 hStay1 | |
| have hfib_le_c : Nat.fib (k0 + 4) ≤ c := by | |
| simpa only [r1] using fib_four_le_of_lt_and_mod c m k0 hm_pos hcm hm_lower hr1_lower | |
| simpa only [Nat.succ_eq_add_one, Nat.add_assoc] using hfib_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 反復の停止上界。 | |
| -/ | |
| private lemma euclidN_c_zero_of_lt_fib (c m k : Nat) | |
| (h : m < Nat.fib (k + 2)) : | |
| (Fuel.euclidN k c m).2 = 0 := by | |
| by_contra hk | |
| exact (not_lt_of_ge <| | |
| euclidN_fib_lower c m k (fun i hi => euclidN_nonzero_of_le c m k i hk hi)) h | |
| /-- | |
| 入力/前提: `m ≤ n`。 | |
| 主張: `m < fib (n+2)`。 | |
| 内容: `n < n+1 ≤ fib (n+2)` を介して従う。 | |
| 証明: `Nat.le_fib_add_one (n+2)` から `n+1 ≤ fib (n+2)` を得る。 | |
| 役割: `euclidN_c_zero_of_le` を Fibonacci 上界版へ還元する補助。 | |
| -/ | |
| private lemma lt_fib_add_two_of_le {m n : Nat} (h : m ≤ n) : | |
| m < Nat.fib (n + 2) := by | |
| have hn1_le : n + 1 ≤ Nat.fib (n + 2) := by | |
| have := Nat.le_fib_add_one (n + 2) | |
| omega | |
| have hn_lt : n < Nat.fib (n + 2) := | |
| lt_of_lt_of_le (Nat.lt_succ_self n) hn1_le | |
| exact lt_of_le_of_lt h hn_lt | |
| /-- | |
| 入力/前提: c m n : Nat、h : m <= n。 | |
| 主張: `m ≤ n` なら `(euclidN n c m).2 = 0`。 | |
| 内容: root 側の Fibonacci 上界版停止補題へ還元する。 | |
| 証明: `m < fib (n+2)` を作って `euclidN_c_zero_of_lt_fib` を適用する。 | |
| 役割: `euclidN_exists_c_zero` など Internal API から使う停止上界。 | |
| -/ | |
| private lemma euclidN_c_zero_of_le (c m n : Nat) (h : m <= n) : | |
| (euclidN n c m).2 = 0 := | |
| euclidN_c_zero_of_lt_fib c m n (lt_fib_add_two_of_le h) | |
| /-- | |
| 入力/前提: `c m : Nat`。 | |
| 主張: ある時刻 `t` で Euclid 反復の第2成分は 0 になる。 | |
| 内容: `t = m` を取れば `m ≤ m` から `euclidN_c_zero_of_le` が使える。 | |
| 証明: 具体的証人 `m` を与える。 | |
| 役割: `euclidTau`(`Nat.find`)の存在仮定。 | |
| -/ | |
| private lemma euclidN_exists_c_zero (c m : Nat) : | |
| ∃ t, (euclidN t c m).2 = 0 := | |
| ⟨m, euclidN_c_zero_of_le c m m le_rfl⟩ | |
| end Internal | |
| /-- | |
| 目的: 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 (Internal.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 := | |
| Nat.find_spec (Internal.euclidN_exists_c_zero c m) | |
| namespace Internal | |
| /-- | |
| 入力/前提: `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` を適用する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 停止性の単調性(後方不変性)。 | |
| -/ | |
| private 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 := | |
| euclidN_c_zero_mono c m i j hij hi0 | |
| /-- | |
| 入力/前提: `c m t : Nat`、`ht : (euclidN t c m).2 = 0`。 | |
| 主張: `euclidTau c m ≤ t`。 | |
| 内容: `Nat.find_min'` で最小性を得る。 | |
| 証明: `Nat.find` の最小性。 | |
| 役割: 停止時刻の最小性を与える。 | |
| -/ | |
| private lemma euclidTau_le_of_c_zero (c m t : Nat) | |
| (ht : (euclidN t c m).2 = 0) : | |
| euclidTau c m ≤ t := | |
| Nat.find_min' (euclidN_exists_c_zero c m) ht | |
| /-- | |
| 入力/前提: `c m k : Nat`。 | |
| 主張: `euclidTau c m ≤ k` と `(euclidN k c m).2 = 0` は同値。 | |
| 内容: 前向きは停止性の単調性、後向きは `Nat.find` の最小性。 | |
| 証明: 既存補題の合成。 | |
| 役割: tex での「`\tau \le k`」と Lean の停止判定を接続する基礎同値。 | |
| -/ | |
| private lemma euclidTau_le_iff_c_zero (c m k : Nat) : | |
| euclidTau c m ≤ k ↔ (euclidN k c m).2 = 0 := | |
| ⟨fun hle => euclidN_c_zero_of_le_index c m (euclidTau c m) k hle (euclidTau_spec c m), | |
| euclidTau_le_of_c_zero c m k⟩ | |
| /-- | |
| 入力/前提: `c m k : Nat`、`euclidTau c m ≤ k`。 | |
| 主張: 最小停止時刻以上では `(euclidN k c m).2 = 0`。 | |
| 内容: `euclidTau_le_iff_c_zero` の前向き射影を名前付き補題として切り出す。 | |
| 証明: 同値補題に `Iff.mp` を適用する。 | |
| 役割: 停止時刻上界から停止を読む箇所で `(...).1` を避ける。 | |
| -/ | |
| private lemma euclidN_c_zero_of_tau_le (c m k : Nat) | |
| (hk : euclidTau c m ≤ k) : | |
| (euclidN k c m).2 = 0 := | |
| Iff.mp (euclidTau_le_iff_c_zero c m k) hk | |
| /-- | |
| 入力/前提: `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` に対応する停止時刻版。 | |
| -/ | |
| private lemma euclidTau_le_of_lt_fib (c m k : Nat) | |
| (h : m < Nat.fib (k + 2)) : | |
| euclidTau c m ≤ k := | |
| euclidTau_le_of_c_zero c m k (euclidN_c_zero_of_lt_fib c m k h) | |
| /-- | |
| 入力/前提: `m : Nat`。 | |
| 主張: `stepBoundOfM m = greatestFib m - 1`。 | |
| 内容: `greatestFibBinary_spec` を展開して定義式をそのまま読む。 | |
| 証明: `simp` で `greatestFibBinary_spec` を展開する。 | |
| 役割: `stepBoundOfM` を `greatestFib` の添字へ書き換える共通補題。 | |
| -/ | |
| private lemma stepBoundOfM_eq_greatestFib_pred (m : Nat) (_hm : 0 < m) : | |
| Fuel.stepBoundOfM m = Nat.greatestFib m - 1 := by | |
| simp [Fuel.stepBoundOfM, Fib.Core.greatestFibBinary_spec] | |
| /-- | |
| 入力/前提: `m : Nat`、`hm : 0 < m`。 | |
| 主張: `stepBoundOfM m + 2 = greatestFib m + 1`。 | |
| 内容: `stepBoundOfM = greatestFib - 1` の書換えに 2 を足した形。 | |
| 証明: `stepBoundOfM_eq_greatestFib_pred` の後を `omega` で整える。 | |
| 役割: `lt_fib_stepBoundOfM_add_two` で Fibonacci の添字を直接置き換える。 | |
| -/ | |
| private lemma stepBoundOfM_add_two_eq_greatestFib_add_one (m : Nat) (hm : 0 < m) : | |
| Fuel.stepBoundOfM m + 2 = 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 | |
| rw [stepBoundOfM_eq_greatestFib_pred m hm] | |
| omega | |
| /-- | |
| 入力/前提: `m : Nat`、`hm : 0 < m`。 | |
| 主張: `m < fib (stepBoundOfM m + 2)`。 | |
| 内容: `stepBoundOfM m = greatestFib m - 1` と | |
| `m < fib (greatestFib m + 1)` をつなぐ添字変換。 | |
| 証明: `Nat.lt_fib_greatestFib_add_one` と `greatestFibBinary_spec` の書換え。 | |
| 役割: `euclidTau_le_stepBoundOfM` を直接 `euclidTau_le_of_lt_fib` に落とす補助。 | |
| -/ | |
| private lemma lt_fib_stepBoundOfM_add_two (m : Nat) (hm : 0 < m) : | |
| m < Nat.fib (Fuel.stepBoundOfM m + 2) := by | |
| simpa only [stepBoundOfM_add_two_eq_greatestFib_add_one m hm] using | |
| (Nat.lt_fib_greatestFib_add_one m) | |
| /-- | |
| 入力/前提: `c m : Nat`、`hm : 0 < m`。 | |
| 主張: `stepBoundOfM m` は最小停止時刻 `euclidTau c m` の上界。 | |
| 内容: `stepBoundOfM = Nat.greatestFib - 1` を使って `euclidTau_le_greatestFib_pred` に帰着する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 実装上の反復上界 `stepBoundOfM` と厳密停止時刻評価を接続する。 | |
| -/ | |
| private lemma euclidTau_le_stepBoundOfM (c m : Nat) (hm : 0 < m) : | |
| Fuel.euclidTau c m ≤ Fuel.stepBoundOfM m := by | |
| exact euclidTau_le_of_lt_fib c m (Fuel.stepBoundOfM m) | |
| (lt_fib_stepBoundOfM_add_two m hm) | |
| /-- | |
| 入力/前提: `z : Int`、`hz : 0 < z`。 | |
| 主張: `Int.toNat z` は正。 | |
| 内容: `Int.toNat z = 0` なら `z ≤ 0` と矛盾する。 | |
| 証明: `Int.toNat_eq_zero` に帰着する。 | |
| 役割: `stepBoundOfM` の正性や燃料の非零性を示す補助。 | |
| -/ | |
| private lemma int_toNat_pos_of_pos {z : Int} (hz : 0 < z) : 0 < Int.toNat z := by | |
| exact Nat.pos_of_ne_zero (int_toNat_ne_zero_of_pos hz) | |
| /-- | |
| 入力/前提: `m : Nat`、`hm : 0 < m`。 | |
| 主張: `Nat.greatestFib m ≥ 2`。 | |
| 内容: `fib 2 = 1 ≤ m` を `Nat.le_greatestFib` に流し込んだ形。 | |
| 証明: `Nat.fib_two` と `Nat.le_greatestFib` を組み合わせる。 | |
| 役割: `stepBoundOfM_pos` と `stepN_bound_c_zero` の添字下界を共通化する。 | |
| -/ | |
| private lemma greatestFib_ge_two_of_pos (m : Nat) (hm : 0 < m) : | |
| 2 ≤ Nat.greatestFib m := by | |
| have hfib2_le : Nat.fib 2 ≤ m := by | |
| simpa only [Nat.fib_two] using (Nat.succ_le_of_lt hm) | |
| exact (Nat.le_greatestFib (m := 2) (n := m)).2 hfib2_le | |
| /-- | |
| 入力/前提: `m : Nat`、`hm : 0 < m`。 | |
| 主張: `stepBoundOfM m` は正。 | |
| 内容: `greatestFib m ≥ 2` を用いて `greatestFibBinary m - 1 > 0` を得る。 | |
| 証明: `greatestFib_ge_two_of_pos` と `stepBoundOfM_eq_greatestFib_pred` を使う。 | |
| 役割: `mwf_iter_correct` で燃料が 0 でないことを示す補助。 | |
| -/ | |
| private lemma stepBoundOfM_pos (m : Nat) (hm : 0 < m) : 0 < Fuel.stepBoundOfM m := by | |
| have hg_ge2 : 2 ≤ Nat.greatestFib m := greatestFib_ge_two_of_pos m hm | |
| rw [stepBoundOfM_eq_greatestFib_pred m hm] | |
| omega | |
| /-- | |
| 入力/前提: `U : St`、`(step U).c ≠ 0`。 | |
| 主張: `stPairNat (step U)` の第1成分は `Int.toNat U.m` に等しく、第2成分はそれより小さい。 | |
| 内容: `step` が停止しない場合、`c := m` かつ `m` は真に減少する。 | |
| 証明: `step_c_or` と `mwf_step_reduce_reduction` を組み合わせて `Int.toNat` に落とす。 | |
| 役割: `stepN_bound_c_zero` で Euclid 側の `m<c` 前提をまとめて作る。 | |
| -/ | |
| private lemma stPairNat_step_bounds_of_nonzero (U : Impl.St) | |
| (hc : (Impl.Internal.step U).c ≠ 0) : | |
| (stPairNat (Impl.Internal.step U)).1 = Int.toNat U.m | |
| ∧ (stPairNat (Impl.Internal.step U)).2 < (stPairNat (Impl.Internal.step U)).1 := by | |
| have hdec : (Impl.Internal.step U).m < U.m := by | |
| cases Mwf.Internal.mwf_step_reduce_reduction U with | |
| | inl h => exact h | |
| | inr h0 => exact False.elim (hc h0) | |
| have hdec_nat : Int.toNat (Impl.Internal.step U).m < Int.toNat U.m := by | |
| exact (Int.toNat_lt_toNat U.hm).2 hdec | |
| have hY0_ne : Impl.Internal.stnorm_y (Impl.Internal.step_normalize U) ≠ 0 := by | |
| intro hY0 | |
| exact hc (Mwf.Internal.step_c_eq_zero_of_stnorm_y_eq_zero U hY0) | |
| have hstep_c_eq : (Impl.Internal.step U).c = U.m := by | |
| exact Mwf.Internal.step_c_eq_m_of_stnorm_y_ne_zero U hY0_ne | |
| constructor | |
| · simpa only [stPairNat] using congrArg Int.toNat hstep_c_eq | |
| · simpa only [stPairNat, hstep_c_eq] using hdec_nat | |
| /-- | |
| 入力/前提: `step U` から `t` 回まで `c ≠ 0` が続く。 | |
| 主張: 対応する Euclid 反復でも `t` 回まで第2成分は 0 にならない。 | |
| 内容: `stepN_eq_euclidN` で対応付け、`stepN` 側 state の `m>0` から第2成分の非零性を得る。 | |
| 証明: 各時刻 `i` ごとに対応等式の第2成分を比較する。 | |
| 役割: `stepN_bound_c_zero` で `euclidN_fib_lower_first_of_lt` を適用する前提を供給する。 | |
| -/ | |
| private lemma euclidN_nonzero_of_step_stay (U : Impl.St) (t : Nat) | |
| (hStay : ∀ i, i ≤ t → (stepN i (Impl.Internal.step U)).c ≠ 0) : | |
| ∀ i, i ≤ t → | |
| (Fuel.euclidN i (stPairNat (Impl.Internal.step U)).1 | |
| (stPairNat (Impl.Internal.step U)).2).2 ≠ 0 := by | |
| intro i hi | |
| have hEq : | |
| stPairNat (stepN i (Impl.Internal.step U)) = | |
| Fuel.euclidN i (stPairNat (Impl.Internal.step U)).1 | |
| (stPairNat (Impl.Internal.step U)).2 := by | |
| apply stepN_eq_euclidN U i | |
| intro j hj | |
| exact hStay j (le_trans hj hi) | |
| have hstepN_m_ne0 : Int.toNat (stepN i (Impl.Internal.step U)).m ≠ 0 := | |
| int_toNat_ne_zero_of_pos (stepN i (Impl.Internal.step U)).hm | |
| intro hz0 | |
| exact hstepN_m_ne0 ((congrArg Prod.snd hEq).trans hz0) | |
| /-- | |
| 入力/前提: `step U` から始まる非停止列。 | |
| 主張: 特に `(step U).c ≠ 0`。 | |
| 内容: `i = 0` の場合を読むだけ。 | |
| 証明: `stepN 0 = id` を `simpa` で展開する。 | |
| 役割: `stepN_bound_c_zero` で `stPairNat_step_bounds_of_nonzero` に渡す前提を作る。 | |
| -/ | |
| private lemma step_c_nonzero_of_step_stay (U : Impl.St) (t : Nat) | |
| (hStay : ∀ i, i ≤ t → (stepN i (Impl.Internal.step U)).c ≠ 0) : | |
| (Impl.Internal.step U).c ≠ 0 := by | |
| simpa only [stepN] using hStay 0 (Nat.zero_le _) | |
| /-- | |
| 入力/前提: `step U` が非停止で、その後も `g-2` 回までは停止しない。 | |
| 主張: `fib (g+1) ≤ Int.toNat U.m`。 | |
| 内容: `stPairNat (step U)` に対する `euclidN_fib_lower_first_of_lt` を | |
| `stPairNat_step_bounds_of_nonzero` で元の `m` に戻す。 | |
| 証明: Euclid 側の非停止列へ移送し、添字整形のあと成分等式で書き戻す。 | |
| 役割: `stepN_bound_c_zero` の中心矛盾構成を helper 化する。 | |
| -/ | |
| private lemma fib_greatestFib_add_one_le_of_step_stay (U : Impl.St) (g : Nat) | |
| (hg_ge2 : 2 ≤ g) (hstep_c_ne : (Impl.Internal.step U).c ≠ 0) | |
| (hStayStep : ∀ i, i ≤ g - 2 → (stepN i (Impl.Internal.step U)).c ≠ 0) : | |
| Nat.fib (g + 1) ≤ Int.toNat U.m := by | |
| have hpair := stPairNat_step_bounds_of_nonzero U hstep_c_ne | |
| have hFib_le : | |
| Nat.fib ((g - 2) + 3) ≤ (stPairNat (Impl.Internal.step U)).1 := | |
| euclidN_fib_lower_first_of_lt | |
| (stPairNat (Impl.Internal.step U)).1 | |
| (stPairNat (Impl.Internal.step U)).2 | |
| (g - 2) hpair.2 (euclidN_nonzero_of_step_stay U (g - 2) hStayStep) | |
| have hidx : (g - 2) + 3 = g + 1 := by omega | |
| have h' : Nat.fib (g + 1) ≤ (stPairNat (Impl.Internal.step U)).1 := by | |
| simpa only [hidx] using hFib_le | |
| exact h'.trans_eq (by simpa using hpair.1) | |
| /-- | |
| 入力/前提: `g ≥ 2` かつ `(stepN (g - 1) U).c ≠ 0`。 | |
| 主張: `fib (g+1) ≤ Int.toNat U.m`。 | |
| 内容: 終端時刻での非停止仮定から、`U` と `step U` の非停止列を作って | |
| `fib_greatestFib_add_one_le_of_step_stay` に渡す。 | |
| 証明: `stepN_nonzero_of_le`, `stepN_stay_from_succ`, `step_c_nonzero_of_step_stay` | |
| の合成。 | |
| 役割: `stepN_bound_c_zero` から中間の非停止列構成を追い出す。 | |
| -/ | |
| private lemma fib_greatestFib_add_one_le_of_stepN_nonzero (U : Impl.St) (g : Nat) | |
| (hg_ge2 : 2 ≤ g) (hk_non : (stepN (g - 1) U).c ≠ 0) : | |
| Nat.fib (g + 1) ≤ Int.toNat U.m := by | |
| 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 (Impl.Internal.step U)).c ≠ 0 := | |
| stepN_stay_from_succ U (g - 2) (fun i hi => hStayU i (by omega)) | |
| have hstep_c_ne : (Impl.Internal.step U).c ≠ 0 := | |
| step_c_nonzero_of_step_stay U (g - 2) hStayStep | |
| exact fib_greatestFib_add_one_le_of_step_stay U g hg_ge2 hstep_c_ne hStayStep | |
| /-- | |
| 入力/前提: 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` より妥当)。 | |
| -/ | |
| private theorem stepN_bound_c_zero (U : Impl.St) : | |
| (stepN (Fuel.stepBoundOfM (Int.toNat U.m)) U).c = 0 := by | |
| set m0 : Nat := Int.toNat U.m | |
| set g : Nat := Nat.greatestFib m0 | |
| have hm0_pos : 0 < m0 := by | |
| simpa only [m0] using int_toNat_pos_of_pos U.hm | |
| have hk : Fuel.stepBoundOfM m0 = g - 1 := by | |
| simpa only [g] using stepBoundOfM_eq_greatestFib_pred m0 hm0_pos | |
| have hg_ge2 : 2 ≤ g := by | |
| simpa only [g] using greatestFib_ge_two_of_pos m0 hm0_pos | |
| by_contra hnonzero | |
| have hk_non : (stepN (g - 1) U).c ≠ 0 := by | |
| simpa only [m0, hk, ne_eq] using hnonzero | |
| have hFib_le_m0 : Nat.fib (g + 1) ≤ m0 := by | |
| simpa only [m0] using fib_greatestFib_add_one_le_of_stepN_nonzero U g hg_ge2 hk_non | |
| 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 | |
| end Internal | |
| end Fuel | |
| namespace Correctness | |
| namespace Internal | |
| /-- | |
| 入力/前提: `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` の中核補題。 | |
| -/ | |
| private lemma mwf_iter_aux_correct (k : Nat) (U : Impl.St) | |
| (h : (Fuel.Internal.stepN (k + 1) U).c = 0) : | |
| Impl.Internal.mwf_iter_aux (k + 1) U = max U.r (U.s + Impl.Internal.st_mwf U) := by | |
| induction k generalizing U with | |
| | zero => | |
| by_cases h0 : U.c = 0 | |
| · simpa only using Mwf.Internal.mwf_iter_aux_value_of_c_zero 0 U h0 | |
| · have h1 : (Impl.Internal.step U).c = 0 := by | |
| simpa only [Fuel.Internal.stepN] using h | |
| have hstep : | |
| Impl.Internal.mwf_iter_aux 0 (Impl.Internal.step U) = | |
| max (Impl.Internal.step U).r ((Impl.Internal.step U).s + Impl.Internal.st_mwf | |
| (Impl.Internal.step U)) := by | |
| simpa only [Impl.Internal.mwf_iter_aux] | |
| using (Mwf.Internal.step_tail_eq_of_step_c_zero U h1).symm | |
| simpa only using Mwf.Internal.mwf_iter_aux_step_correct_of_c_ne 0 U h0 hstep | |
| | succ k ih => | |
| by_cases h0 : U.c = 0 | |
| · simpa only [Nat.succ_eq_add_one, Nat.add_assoc] using | |
| Mwf.Internal.mwf_iter_aux_value_of_c_zero (k + 1) U h0 | |
| · have h' : (Fuel.Internal.stepN (k + 1) (Impl.Internal.step U)).c = 0 := by | |
| simpa only [Fuel.Internal.stepN] using h | |
| simpa only [Nat.succ_eq_add_one, Nat.add_assoc] using | |
| Mwf.Internal.mwf_iter_aux_step_correct_of_c_ne (k + 1) U h0 | |
| (ih (U := Impl.Internal.step U) h') | |
| /-- | |
| 入力/前提: 正の fuel `k` と `(stepN k U).c = 0`。 | |
| 主張: `mwf_iter_aux k U` は保存量 `max U.r (U.s + st_mwf U)` を返す。 | |
| 内容: `k = k' + 1` と書き直して `mwf_iter_aux_correct` を適用する薄い wrapper。 | |
| 証明: `Nat.exists_eq_succ_of_ne_zero` で `k` を分解して既存補題へ還元する。 | |
| 役割: `mwf_iter_correct` から fuel 分解の雑音を除く。 | |
| -/ | |
| private lemma mwf_iter_aux_correct_of_pos (k : Nat) (hk : 0 < k) (U : Impl.St) | |
| (h : (Fuel.Internal.stepN k U).c = 0) : | |
| Impl.Internal.mwf_iter_aux k U = max U.r (U.s + Impl.Internal.st_mwf U) := by | |
| obtain ⟨k', hk'⟩ := Nat.exists_eq_succ_of_ne_zero (Nat.ne_of_gt hk) | |
| simpa only [hk'] using (mwf_iter_aux_correct k' U (by simpa only [hk'] using h)) | |
| /-- | |
| 入力/前提: `N M A B C D : Int`, `hN : 0 < N`, `hM : 0 < M`。 | |
| 主張: 初期状態に対する `mwf_iter_aux` は `mwf` を返す。 | |
| 内容: 停止上界付きの `mwf_iter_aux_correct_of_pos` と `Mwf_step_init_equiv` を初期状態で合成する。 | |
| 証明: 初期状態 `U` をおいて、反復補題と初期値補題を順に適用する。 | |
| 役割: `mwf_iter_correct` から初期状態まわりの局所準備を取り除く。 | |
| -/ | |
| private lemma mwf_iter_aux_correct_init | |
| (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| Impl.Internal.mwf_iter_aux (Fuel.stepBoundOfM (Int.toNat M)) | |
| (Impl.St.mk (B * Spec.zfloorDiv D M hM) 0 N M A B C D hN hM) = | |
| mwf N M A B C D hN hM := by | |
| let U : Impl.St := Impl.St.mk (B * Spec.zfloorDiv D M hM) 0 N M A B C D hN hM | |
| have hinit : max U.r (U.s + Impl.Internal.st_mwf U) = mwf N M A B C D hN hM := by | |
| simpa only [Spec.zfloorDiv, Impl.Internal.st_mwf, U, mwf, Spec.img, Spec.obj, Spec.dom, | |
| zero_add, sup_eq_right] using (Mwf.Internal.Mwf_step_init_equiv N M A B C D hN hM).symm | |
| have hiter : | |
| Impl.Internal.mwf_iter_aux (Fuel.stepBoundOfM (Int.toNat U.m)) U = | |
| max U.r (U.s + Impl.Internal.st_mwf U) := by | |
| exact mwf_iter_aux_correct_of_pos | |
| (Fuel.stepBoundOfM (Int.toNat U.m)) | |
| (Fuel.Internal.stepBoundOfM_pos (Int.toNat U.m) | |
| (Fuel.Internal.int_toNat_pos_of_pos U.hm)) | |
| U | |
| (Fuel.Internal.stepN_bound_c_zero U) | |
| exact hiter.trans hinit | |
| end Internal | |
| /-- | |
| 入力/前提: N M A B C D : Int、hN : 0 < N、hM : 0 < M。 | |
| 主張: 反復実装 `Impl.mwf_iter` は定義的な `mwf` と一致する。 | |
| 内容: `Impl.Internal.stepN_bound_c_zero` と `Impl.Internal.mwf_iter_aux_correct` を組み合わせて示す。 | |
| 証明: 場合分け・既存補題の書き換えで示す。 | |
| 役割: 実装の正しさ保証。 | |
| -/ | |
| theorem mwf_iter_correct | |
| (N M A B C D : Int) (hN : 0 < N) (hM : 0 < M) : | |
| Impl.mwf_iter N M A B C D hN hM = mwf N M A B C D hN hM := by | |
| simpa only [Impl.mwf_iter, Spec.zfloorDiv, mwf, Spec.img, Spec.obj, Spec.dom] using | |
| Internal.mwf_iter_aux_correct_init N M A B C D hN hM | |
| namespace Internal | |
| /-- | |
| 入力/前提: 線形順序型 `α` 上の有限集合 `s,t` とその非空性。 | |
| 主張: `s = t` なら `max'` も一致する。 | |
| 内容: 集合等式と証明の一意性から `max'` を移す。 | |
| 証明: 場合分けと proof irrelevance。 | |
| 役割: `mwfLr_iter_correct` で像の書換え後の `max'` を比較する。 | |
| -/ | |
| private lemma max'_congr {α : Type _} [LinearOrder α] | |
| {s t : Finset α} (hs : s.Nonempty) (ht : t.Nonempty) (h : s = t) : | |
| s.max' hs = t.max' ht := by | |
| subst h | |
| cases Subsingleton.elim hs ht | |
| rfl | |
| /-- | |
| 入力/前提: `t : Int`, `m > 0`。 | |
| 主張: `t = m * ⌊t/m⌋ + (t mod m)`。 | |
| 内容: `Spec.zfloorDiv` / `Spec.zfloorMod` が `Int.ediv` / `Int.emod` の薄いラッパであることを明示する。 | |
| 証明: `Int.emod_add_mul_ediv` をそのまま書き換える。 | |
| 役割: `mwfLr_iter_translate` で商剰余分解の局所導入を 1 行にまとめる。 | |
| -/ | |
| private lemma zfloorDiv_mod_decomp (t m : Int) (hM : 0 < m) : | |
| t = m * Spec.zfloorDiv t m hM + Spec.zfloorMod t m hM := by | |
| simpa only [Spec.zfloorDiv, Spec.zfloorMod, mul_comm, add_comm] using | |
| (Int.emod_add_mul_ediv t m).symm | |
| /-- | |
| 入力/前提: `c*l+d = m*q+d'`。 | |
| 主張: 平行移動後の床除算は `q` だけずれる。 | |
| 内容: 加法と商剰余分解を整理する。 | |
| 証明: `Int.add_mul_ediv_left` と環の計算。 | |
| 役割: `mwfLr_iter_correct` の `obj` 変換の基礎。 | |
| -/ | |
| private lemma zfloorDiv_translate | |
| (l m c d q d' t : Int) (hM : 0 < m) | |
| (hqd : c * l + d = m * q + d') : | |
| Spec.zfloorDiv (c * (l + t) + d) m hM = | |
| q + Spec.zfloorDiv (c * t + d') m hM := by | |
| have hm0 : m ≠ 0 := ne_of_gt hM | |
| unfold Spec.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 + Spec.zfloorDiv (c * t + d') m hM := by rfl | |
| /-- | |
| 入力/前提: `c*l+d = m*q+d'`。 | |
| 主張: 区間平行移動後の `obj` は定数項 `cst` と原点基準の `obj` に分解できる。 | |
| 内容: `zfloorDiv_translate` を `obj` 展開へ代入する。 | |
| 証明: 式変形。 | |
| 役割: `mwfLr_iter_correct` の像変換に使う。 | |
| -/ | |
| private lemma obj_translate | |
| (l m a b c d q d' cst t : Int) (hM : 0 < m) | |
| (hqd : c * l + d = m * q + d') (hcst : cst = a * l + b * q) : | |
| Spec.obj a b c d m (l + t) hM = | |
| cst + Spec.obj a b c d' m t hM := by | |
| subst cst | |
| unfold Spec.obj | |
| rw [zfloorDiv_translate l m c d q d' t hM hqd] | |
| ring | |
| /-- | |
| 入力/前提: `n = r-l`。 | |
| 主張: 区間 `[l,r)` の整数点集合は `[0,n)` を `l` だけ平行移動した像に一致する。 | |
| 内容: `x ↔ x-l` の対応を取る。 | |
| 証明: `Finset.ext` と区間不等式の変形。 | |
| 役割: `mwfLr_iter_correct` で `domLr` を `dom` へ移す。 | |
| -/ | |
| private lemma domLr_eq_image_add | |
| (l r n : Int) (hLR : l < r) (hN : 0 < n) (hn : n = r - l) : | |
| Spec.domLr l r hLR = (Spec.dom n hN).image (fun t => l + t) := by | |
| subst n | |
| 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 := sub_nonneg.mpr hx'.1 | |
| have h1 : x - l ≤ r - l - 1 := by nlinarith [hx'.2] | |
| simpa only [Spec.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 ≤ r - l - 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⟩ | |
| /-- | |
| 入力/前提: `n = r-l`, `c*l+d = m*q+d'`, `cst = a*l+b*q`。 | |
| 主張: 区間版の像は、原点基準 `img` に定数 `cst` を足した像に一致する。 | |
| 内容: `domLr_eq_image_add` と `obj_translate` を合成する。 | |
| 証明: 画像の書換え。 | |
| 役割: `mwfLr_iter_correct` の `max'` 比較を可能にする。 | |
| -/ | |
| private lemma imgLr_eq_image_translate | |
| (l r n m a b c d q d' cst : Int) | |
| (hLR : l < r) (hN : 0 < n) (hM : 0 < m) | |
| (hn : n = r - l) (hqd : c * l + d = m * q + d') (hcst : cst = a * l + b * q) : | |
| Spec.imgLr l r m a b c d hLR hM = | |
| (Spec.dom n hN).image (fun t => cst + Spec.obj a b c d' m t hM) := by | |
| calc | |
| Spec.imgLr l r m a b c d hLR hM = | |
| (Spec.domLr l r hLR).image (fun x => Spec.obj a b c d m x hM) := by rfl | |
| _ = ((Spec.dom n hN).image (fun t => l + t)).image (fun x => Spec.obj a b c d m x hM) := by | |
| rw [domLr_eq_image_add l r n hLR hN hn] | |
| _ = (Spec.dom n hN).image ((fun x => Spec.obj a b c d m x hM) ∘ fun t => l + t) := by | |
| rw [Finset.image_image] | |
| _ = (Spec.dom n hN).image (fun t => Spec.obj a b c d m (l + t) hM) := by rfl | |
| _ = (Spec.dom n hN).image (fun t => cst + Spec.obj a b c d' m t hM) := by | |
| refine Finset.image_congr ?_ | |
| intro t ht | |
| exact obj_translate l m a b c d q d' cst t hM hqd hcst | |
| /-- | |
| 入力/前提: `S = img ...`, `f x = cst + x`。 | |
| 主張: 平行移動済みの像は `S.image f` と一致する。 | |
| 内容: `img` の定義と `Finset.image_image` を展開する。 | |
| 証明: 定義展開。 | |
| 役割: `mwfLr_iter_correct` で `Monotone.map_finset_max'` を使う準備。 | |
| -/ | |
| private lemma img_eq_image_add | |
| (n m a b c d cst : Int) (hN : 0 < n) (hM : 0 < m) : | |
| (Spec.dom n hN).image (fun t => cst + Spec.obj a b c d m t hM) = | |
| (Spec.img n m a b c d hN hM).image (fun x => cst + x) := by | |
| simp only [Spec.img, Spec.obj, Spec.zfloorDiv, Spec.dom] | |
| rw [Finset.image_image] | |
| rfl | |
| /-- | |
| 入力/前提: 整数値有限集合 `s` とその非空性。 | |
| 主張: 各要素へ定数 `cst` を足した像の `max'` は、元の `max'` に `cst` を足したものに等しい。 | |
| 内容: `x ↦ cst + x` は単調なので `Monotone.map_finset_max'` を適用できる。 | |
| 証明: 単調性を示して既存補題へ帰着する。 | |
| 役割: `mwfLr_translate_eq_mwf` の `max'` 移送を 1 行で使えるようにする。 | |
| -/ | |
| private lemma max'_image_add_eq (s : Finset Int) (hs : s.Nonempty) (cst : Int) : | |
| (s.image (fun x => cst + x)).max' (hs.image (fun x => cst + x)) = cst + s.max' hs := by | |
| have hmono : Monotone (fun x : Int => cst + x) := by | |
| intro x y hxy | |
| linarith | |
| simpa only [add_comm, Finset.image_add_right, neg_add_rev, add_assoc] using | |
| (Monotone.map_finset_max' (s := s) (f := fun x => cst + x) hmono hs).symm | |
| /-- | |
| 入力/前提: `img` の各値へ定数 `cst` を加えた像。 | |
| 主張: その `max'` は `cst + mwf` に一致する。 | |
| 内容: `img` の非空性と `max'_image_add_eq` を `mwf` の定義へ接続する。 | |
| 証明: `S := img ...` と置いて既存補題を合成する。 | |
| 役割: `mwfLr_translate_eq_mwf` で原点基準 `mwf` 側の `max'` 評価を 1 行で使う。 | |
| -/ | |
| private lemma img_max'_image_add_eq_mwf | |
| (n m a b c d cst : Int) (hN : 0 < n) (hM : 0 < m) : | |
| ((Spec.img n m a b c d hN hM).image (fun x => cst + x)).max' | |
| ((Spec.img_nonempty (N := n) (M := m) (A := a) (B := b) (C := c) (D := d) hN hM).image | |
| (fun x => cst + x)) = | |
| cst + mwf n m a b c d hN hM := by | |
| simpa only [mwf] using | |
| max'_image_add_eq | |
| (Spec.img n m a b c d hN hM) | |
| (Spec.img_nonempty (N := n) (M := m) (A := a) (B := b) (C := c) (D := d) hN hM) | |
| cst | |
| /-- | |
| 入力/前提: `img` の各値へ定数 `cst` を加えた像。 | |
| 主張: その像は非空である。 | |
| 内容: `img_nonempty` の witness をそのまま `image` に送る。 | |
| 証明: `Finset.Nonempty.image` の直接適用。 | |
| 役割: `mwfLr_translate_eq_mwf` の `max'` 比較で非空性証明を短くする。 | |
| -/ | |
| private lemma img_image_add_nonempty | |
| (n m a b c d cst : Int) (hN : 0 < n) (hM : 0 < m) : | |
| ((Spec.img n m a b c d hN hM).image (fun x => cst + x)).Nonempty := | |
| (Spec.img_nonempty (N := n) (M := m) (A := a) (B := b) (C := c) (D := d) hN hM).image | |
| (fun x => cst + x) | |
| /-- | |
| 入力/前提: `n = r-l`, `c*l+d = m*q+d'`, `cst = a*l+b*q`。 | |
| 主張: 区間版の像は、原点基準 `img` に定数 `cst` を足した像に一致する。 | |
| 内容: `imgLr_eq_image_translate` と `img_eq_image_add` を直接合成した版。 | |
| 証明: 2 本の像変換補題を順に適用する。 | |
| 役割: `mwfLr_translate_eq_mwf` から中間の `dom.image` 形を隠す。 | |
| -/ | |
| private lemma imgLr_eq_img_image_add | |
| (l r n m a b c d q d' cst : Int) | |
| (hLR : l < r) (hN : 0 < n) (hM : 0 < m) | |
| (hn : n = r - l) (hqd : c * l + d = m * q + d') (hcst : cst = a * l + b * q) : | |
| Spec.imgLr l r m a b c d hLR hM = | |
| (Spec.img n m a b c d' hN hM).image (fun x => cst + x) := by | |
| calc | |
| Spec.imgLr l r m a b c d hLR hM | |
| = (Spec.dom n hN).image (fun t => cst + Spec.obj a b c d' m t hM) := by | |
| exact imgLr_eq_image_translate l r n m a b c d q d' cst hLR hN hM hn hqd hcst | |
| _ = (Spec.img n m a b c d' hN hM).image (fun x => cst + x) := by | |
| simpa only using img_eq_image_add n m a b c d' cst hN hM | |
| /-- | |
| 入力/前提: `n = r - l`、`c*l+d = m*q+d'`、`cst = a*l+b*q`。 | |
| 主張: 区間版 `mwfLr` は平行移動後の `mwf` に定数項 `cst` を足した値に一致する。 | |
| 内容: `imgLr` を `[0,n)` 上の像へ移し、`max'` の単調写像で最大値を移送する。 | |
| 証明: `imgLr_eq_image_translate`, `img_eq_image_add`, `Monotone.map_finset_max'` を結合する。 | |
| 役割: `mwfLr_iter_correct` を `mwf_iter_correct` に還元する。 | |
| -/ | |
| private lemma mwfLr_translate_eq_mwf | |
| (l r n m a b c d q d' cst : Int) | |
| (hLR : l < r) (hN : 0 < n) (hM : 0 < m) | |
| (hn : n = r - l) (hqd : c * l + d = m * q + d') (hcst : cst = a * l + b * q) : | |
| mwfLr l r m a b c d hLR hM = cst + mwf n m a b c d' hN hM := by | |
| classical | |
| have hImg : ((Spec.img n m a b c d' hN hM).image (fun x => cst + x)).Nonempty := | |
| img_image_add_nonempty n m a b c d' cst hN hM | |
| have hImgLr : Spec.imgLr l r m a b c d hLR hM = | |
| (Spec.img n m a b c d' hN hM).image (fun x => cst + x) := by | |
| exact imgLr_eq_img_image_add l r n m a b c d q d' cst hLR hN hM hn hqd hcst | |
| calc | |
| mwfLr l r m a b c d hLR hM | |
| = ((Spec.img n m a b c d' hN hM).image (fun x => cst + x)).max' | |
| hImg := by | |
| unfold mwfLr | |
| exact max'_congr | |
| (Spec.imgLr_nonempty (L := l) (R := r) (M := m) (A := a) (B := b) | |
| (C := c) (D := d) hLR hM) | |
| hImg | |
| hImgLr | |
| _ = cst + mwf n m a b c d' hN hM := by | |
| exact img_max'_image_add_eq_mwf n m a b c d' cst hN hM | |
| /-- | |
| 入力/前提: 区間版パラメータ `l,r,m,a,b,c,d` と `l<r`, `m>0`。 | |
| 主張: `mwfLr_iter` と `mwfLr` はともに、平行移動後の `mwf_iter` / `mwf` | |
| に同じ定数項 `cst` を足した形へ書ける。 | |
| 内容: `n = r-l`, `q = ⌊(cl+d)/m⌋`, `d' = (cl+d) % m`, `cst = a*l + b*q` | |
| を導入して、実装側は定義展開、仕様側は `mwfLr_translate_eq_mwf` を使う。 | |
| 証明: Euclid 除算の分解式と既存補題の合成。 | |
| 役割: `mwfLr_iter_correct` から局所的な置換準備を切り離す。 | |
| -/ | |
| private lemma mwfLr_iter_translate | |
| (l r m a b c d : Int) (hLR : l < r) (hM : 0 < m) : | |
| ∃ n : Int, ∃ d' : Int, ∃ cst : Int, ∃ hN : 0 < n, | |
| Impl.mwfLr_iter l r m a b c d hLR hM = cst + Impl.mwf_iter n m a b c d' hN hM ∧ | |
| mwfLr l r m a b c d hLR hM = cst + mwf n m a b c d' hN hM := by | |
| have hN : 0 < r - l := by | |
| nlinarith [hLR] | |
| refine ⟨r - l, Spec.zfloorMod (c * l + d) m hM, | |
| a * l + b * Spec.zfloorDiv (c * l + d) m hM, hN, ?_, ?_⟩ | |
| · simp only [Impl.mwfLr_iter, Spec.zfloorDiv, Spec.zfloorMod] | |
| · exact mwfLr_translate_eq_mwf l r (r - l) m a b c d | |
| (Spec.zfloorDiv (c * l + d) m hM) | |
| (Spec.zfloorMod (c * l + d) m hM) | |
| (a * l + b * Spec.zfloorDiv (c * l + d) m hM) | |
| hLR hN hM rfl | |
| (zfloorDiv_mod_decomp (c * l + d) m hM) rfl | |
| end Internal | |
| /-- | |
| 入力/前提: l r m a b c d : Int、hLR : l < r、hM : 0 < m。 | |
| 主張: 区間版 `mwfLr_iter` は定義的な `mwfLr` と一致する。 | |
| 内容: 置換・商剰余分解で `mwf_iter_correct` に還元する。 | |
| 証明: 場合分け・式変形・既存補題の書き換えで示す。 | |
| 役割: 区間版反復実装の正しさ保証。 | |
| -/ | |
| theorem mwfLr_iter_correct | |
| (l r m a b c d : Int) (hLR : l < r) (hM : 0 < m) : | |
| Impl.mwfLr_iter l r m a b c d hLR hM = | |
| mwfLr l r m a b c d hLR hM := by | |
| classical | |
| obtain ⟨n, d', cst, hN, hiter, hspec⟩ := Internal.mwfLr_iter_translate l r m a b c d hLR hM | |
| rw [hiter, mwf_iter_correct (N := n) (M := m) (A := a) (B := b) (C := c) (D := d') hN hM] | |
| exact hspec.symm | |
| end Correctness | |
| end | |
| namespace Fuel | |
| /-- | |
| 目的: 燃料上界 API 用に `stepN` を `Mwf.Fuel` 配下へ再公開する。 | |
| 定義: `Mwf.Fuel.Internal.stepN` への薄い別名。 | |
| 入力/前提: `k : Nat`, `U : St`。 | |
| 出力: 型 `St` の値を返す。 | |
| 役割: 燃料関連 API を `Mwf.Fuel` に集約する公開面を提供する。 | |
| -/ | |
| abbrev stepN : Nat → Impl.St → Impl.St := Internal.stepN | |
| /-- | |
| 入力/前提: `c m k : Nat`、`hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0`。 | |
| 主張: `k` 回まで未停止なら `Nat.fib (k + 2) ≤ m`。 | |
| 内容: `Internal.euclidN_fib_lower` を `Mwf.Fuel` API として再公開する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 「未停止なら fib 下界が伸びる」公開契約を明示する。 | |
| -/ | |
| theorem euclidN_fib_lower (c m k : Nat) | |
| (hStay : ∀ i, i ≤ k → (euclidN i c m).2 ≠ 0) : | |
| Nat.fib (k + 2) ≤ m := by | |
| simpa only [euclidN] using (Internal.euclidN_fib_lower c m k hStay) | |
| /-- | |
| 入力/前提: `c m k : Nat`、`h : m < Nat.fib (k + 2)`。 | |
| 主張: `m < fib (k+2)` なら `(euclidN k c m).2 = 0`。 | |
| 内容: `Internal.euclidN_c_zero_of_lt_fib` を `Mwf.Fuel` API として再公開する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: fib 比較から「k 回以内停止」を得る公開契約を明示する。 | |
| -/ | |
| theorem euclidN_c_zero_of_lt_fib (c m k : Nat) | |
| (h : m < Nat.fib (k + 2)) : | |
| (euclidN k c m).2 = 0 := by | |
| simpa only [euclidN] using (Internal.euclidN_c_zero_of_lt_fib c m k h) | |
| /-- | |
| 入力/前提: `c m : Nat`、`hm : 0 < m`。 | |
| 主張: `euclidTau c m ≤ stepBoundOfM m`。 | |
| 内容: `Internal.euclidTau_le_stepBoundOfM` を `Mwf.Fuel` API として再公開する。 | |
| 証明: 既存補題の書き換えで示す。 | |
| 役割: 「採用燃料が停止時刻を上から抑える」公開契約を明示する。 | |
| -/ | |
| theorem euclidTau_le_stepBoundOfM (c m : Nat) (hm : 0 < m) : | |
| euclidTau c m ≤ stepBoundOfM m := by | |
| simpa only [euclidTau, stepBoundOfM] using (Internal.euclidTau_le_stepBoundOfM c m hm) | |
| /-- | |
| 入力/前提: `U : St`。 | |
| 主張: `stepBoundOfM (Int.toNat U.m)` 回で `stepN` の `c` は 0 に到達する。 | |
| 内容: `Internal.stepN_bound_c_zero` を `Mwf.Fuel` API として再公開する。 | |
| 証明: 既存定理の書き換えで示す。 | |
| 役割: `Mwf_iter` 側の燃料十分性を公開契約として固定する。 | |
| -/ | |
| theorem stepN_bound_c_zero (U : Impl.St) : | |
| (stepN (stepBoundOfM (Int.toNat U.m)) U).c = 0 := by | |
| simpa only [stepN, stepBoundOfM] using (Internal.stepN_bound_c_zero U) | |
| end Fuel | |
| /- | |
| 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 : α | |
| namespace Spec | |
| /-- | |
| 目的: floor_prod の積そのものによる原義的仕様を定義する。 | |
| 定義: tex の定義どおり、`y^(b/m)` に続けて | |
| `i = 0 .. n-1` の各ブロック `x * y^delta_i` を左から右へ掛ける。 | |
| 入力/前提: `n,m,a,b : Nat`, `[Monoid α]`, 要素 `x,y`。 | |
| 出力: モノイド要素を返す。 | |
| 役割: 論文中の `floor_prod` 定義そのもの。 | |
| -/ | |
| def floorProdFormula {α : Type _} [Monoid α] (n m a b : Nat) (x y : α) : α := | |
| if _hM0 : m = 0 then | |
| x ^ n | |
| else | |
| Nat.rec (motive := fun _ => α) | |
| (y ^ (b / m)) | |
| (fun i acc => | |
| acc * (x * y ^ (((a * (i + 1) + b) / m) - ((a * i + b) / m)))) | |
| n | |
| /-- | |
| 目的: `floorProdFormula` の右端 1 ステップ追加を明示する。 | |
| 定義: `Finset.range (n+1)` を `range n` と末尾 `n` に分解する。 | |
| 入力/前提: `n,m,a,b : Nat`, `[Monoid α]`, 要素 `x,y`。 | |
| 出力: `n+1` 項版を `n` 項版と末尾ブロックに分解した等式を返す。 | |
| 役割: 積仕様から右端更新を直接読む基本補題。 | |
| -/ | |
| lemma floorProdFormula_succ {α : Type _} [Monoid α] | |
| (n m a b : Nat) (x y : α) : | |
| floorProdFormula (n + 1) m a b x y = | |
| floorProdFormula n m a b x y * | |
| (x * y ^ (((a * (n + 1) + b) / m) - ((a * n + b) / m))) := by | |
| by_cases hM0 : m = 0 | |
| · simp [floorProdFormula, hM0, pow_succ] | |
| · simp [floorProdFormula, hM0] | |
| /-- | |
| 入力/前提: `0 < m`。 | |
| 主張: `floorProdFormula` は `a,b` の商と剰余で正規化できる。 | |
| 内容: tex の補題 `floor_prod` の正規化そのもの。 | |
| 役割: `floorProd = floorProdFormula` の direct proof で、while 更新の | |
| `p,q` ステップを仕様側へ移す。 | |
| -/ | |
| lemma floorProdFormula_normalize {α : Type _} [Monoid α] | |
| (n m a b : Nat) (x y : α) (hM : 0 < m) : | |
| floorProdFormula n m a b x y = | |
| y ^ (b / m) * floorProdFormula n m (a % m) (b % m) (x * y ^ (a / m)) y := by | |
| have hquot : | |
| ∀ i : Nat, | |
| (a * i + b) / m = (a / m) * i + b / m + (((a % m) * i + b % m) / m) := by | |
| intro i | |
| have ha : a = m * (a / m) + a % m := (Nat.div_add_mod a m).symm | |
| have hb : b = m * (b / m) + b % m := (Nat.div_add_mod b m).symm | |
| rw [ha, hb] | |
| have hadiv : ((m * (a / m) + a % m) / m) = a / m := by | |
| simpa [Nat.add_comm, Nat.mul_comm] using | |
| (Nat.add_mul_div_right (a % m) (a / m) hM) | |
| have hbdiv : ((m * (b / m) + b % m) / m) = b / m := by | |
| simpa [Nat.add_comm, Nat.mul_comm] using | |
| (Nat.add_mul_div_right (b % m) (b / m) hM) | |
| have hamod : ((m * (a / m) + a % m) % m) = a % m := by | |
| rw [Nat.add_comm] | |
| calc | |
| (a % m + m * (a / m)) % m = (a % m) % m := | |
| Nat.add_mul_mod_self_left (a % m) m (a / m) | |
| _ = a % m := Nat.mod_eq_of_lt (Nat.mod_lt a hM) | |
| have hbmod : ((m * (b / m) + b % m) % m) = b % m := by | |
| rw [Nat.add_comm] | |
| calc | |
| (b % m + m * (b / m)) % m = (b % m) % m := | |
| Nat.add_mul_mod_self_left (b % m) m (b / m) | |
| _ = b % m := Nat.mod_eq_of_lt (Nat.mod_lt b hM) | |
| rw [hadiv, hbdiv, hamod, hbmod] | |
| have hexpr : | |
| (m * (a / m) + a % m) * i + (m * (b / m) + b % m) = | |
| ((a % m) * i + b % m) + m * ((a / m) * i + b / m) := by | |
| ring_nf | |
| rw [hexpr] | |
| have hquot_nat : | |
| (((a % m) * i + b % m) + m * ((a / m) * i + b / m)) / m = | |
| (((a % m) * i + b % m) / m) + ((a / m) * i + b / m) := by | |
| simpa [Nat.mul_comm] using | |
| (Nat.add_mul_div_right ((a % m) * i + b % m) ((a / m) * i + b / m) hM) | |
| rw [hquot_nat] | |
| ac_rfl | |
| induction n with | |
| | zero => | |
| conv_lhs => unfold floorProdFormula | |
| simp [Nat.ne_of_gt hM] | |
| have hb0 : b % m / m = 0 := Nat.div_eq_of_lt (Nat.mod_lt b hM) | |
| simp [floorProdFormula, Nat.ne_of_gt hM, hb0] | |
| | succ n ih => | |
| rw [floorProdFormula_succ, ih] | |
| rw [floorProdFormula_succ] | |
| have h0 := hquot n | |
| have h1 := hquot (n + 1) | |
| have hU : | |
| (((a % m) * n + b % m) / m) ≤ (((a % m) * (n + 1) + b % m) / m) := by | |
| apply Nat.div_le_div_right | |
| exact Nat.add_le_add_right (Nat.mul_le_mul_left _ (Nat.le_succ n)) _ | |
| have hDelta : | |
| ((a * (n + 1) + b) / m) - ((a * n + b) / m) = | |
| a / m + | |
| ((((a % m) * (n + 1) + b % m) / m) - (((a % m) * n + b % m) / m)) := by | |
| set u0 : Nat := (((a % m) * n + b % m) / m) | |
| set u1 : Nat := (((a % m) * (n + 1) + b % m) / m) | |
| have hu : u0 ≤ u1 := by | |
| simp only [u0, u1] | |
| apply Nat.div_le_div_right | |
| exact Nat.add_le_add_right (Nat.mul_le_mul_left _ (Nat.le_succ n)) _ | |
| rw [h1, h0] | |
| have hEq : | |
| (a / m) * (n + 1) + b / m + u1 = | |
| ((a / m) * n + b / m + u0) + (a / m + (u1 - u0)) := by | |
| have huEq : u1 = u0 + (u1 - u0) := by | |
| exact (Nat.add_sub_of_le hu).symm | |
| rw [Nat.mul_add, Nat.mul_one, huEq] | |
| omega | |
| rw [hEq, Nat.add_sub_cancel_left] | |
| rw [hDelta, pow_add] | |
| simp [mul_assoc] | |
| end Spec | |
| namespace Impl | |
| /-- | |
| 目的: 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' | |
| /-- | |
| 目的: `LoopState` を入力に floor_prod 反復を十分な回数だけ実行する。 | |
| 定義: `fuel := Fuel.stepBoundOfM st.m` を選び、`floorProdLoop fuel st` を返す。 | |
| 入力/前提: `[Monoid α]`, `st : LoopState α`。 | |
| 出力: floor_prod の計算結果を返す。 | |
| 役割: 状態入力版の実装エントリとして `floorProd` 本体から利用する。 | |
| 正当性: `Correctness.floorProd_correct` の内部状態版として使う。 | |
| -/ | |
| def floorProdSt {α : Type _} [Monoid α] : LoopState α → α | |
| | st => floorProdLoop (Fuel.stepBoundOfM st.m) st | |
| /-- | |
| 目的: floor_prod 実装エントリを定義する。 | |
| 定義: `sssec:Mwf_floor_prod` の while 更新式を `floorProdLoop` で実行する。 | |
| 入力/前提: `n,m,a,b : Nat`, `[Monoid α]`, 要素 `x,y`。 | |
| 出力: floor_prod の計算結果を返す。 | |
| 役割: floor_prod の実装本体(`floorProd_correct` の左辺)。 | |
| 正当性: `Correctness.floorProd_correct` で仕様 `Spec.floorProdFormula` との一致を示す。 | |
| -/ | |
| 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 } | |
| floorProdSt st | |
| end Impl | |
| namespace Fuel | |
| /-- | |
| 入力/前提: 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) : | |
| (Fuel.euclidN (Fuel.stepBoundOfM m) a m).2 = 0 := by | |
| by_cases hm : 0 < m | |
| · simpa using | |
| Fuel.Internal.euclidN_c_zero_of_tau_le a m (Fuel.stepBoundOfM m) | |
| (Fuel.euclidTau_le_stepBoundOfM a m hm) | |
| · simpa [Nat.eq_zero_of_not_pos hm] using | |
| (Fuel.Internal.euclidN_c_zero_of_le a 0 (Fuel.stepBoundOfM 0) (Nat.zero_le _)) | |
| end Fuel | |
| namespace Internal | |
| /-- | |
| 入力/前提: 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` の直接トリガー補題。 | |
| -/ | |
| private 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) | |
| end Internal | |
| namespace Fuel | |
| /-- | |
| 入力/前提: st : LoopState α。 | |
| 主張: `stepBoundOfM st.m` は `a,m` の Euclid 縮約を 0 余りまで到達させる。 | |
| 内容: `euclidN_second_zero_stepBoundOfM` の状態版。 | |
| 証明: 既存補題の直接適用。 | |
| 役割: `floorProd` に `stepBoundOfM m` を使ってよい根拠(縮約回数側)。 | |
| -/ | |
| theorem floorProdLoop_fuel_sufficient | |
| {α : Type _} [Monoid α] (st : LoopState α) : | |
| (Fuel.euclidN (Fuel.stepBoundOfM st.m) st.a st.m).2 = 0 := by | |
| simpa using Fuel.euclidN_second_zero_stepBoundOfM st.a st.m | |
| end Fuel | |
| namespace Internal | |
| /-- | |
| 入力/前提: `m ≤ y` かつ `m > 0`。 | |
| 主張: `0 < y / m`。 | |
| 内容: 商が 0 でないことを取り出す自然数除算の基本補題。 | |
| 証明: `y / m = 0` と仮定して `m ≤ y` に反することを示す。 | |
| 役割: `floorProd_exponent_bridge` で指数の正性を得る。 | |
| -/ | |
| private lemma floorProd_div_pos_of_ge | |
| (y m : Nat) (hM : 0 < m) (hY : m ≤ y) : | |
| 0 < y / m := by | |
| by_contra hc0 | |
| have hdiv0 : y / m = 0 := Nat.eq_zero_of_not_pos hc0 | |
| rcases (Nat.div_eq_zero_iff.mp hdiv0) with hm0 | hy_lt | |
| · exact False.elim ((Nat.ne_of_gt hM) hm0) | |
| · exact (Nat.not_le_of_lt hy_lt) hY | |
| /-- | |
| 入力/前提: `a > 0`。 | |
| 主張: `k = r / a` とおくと `k * a ≤ r ≤ k * a + a - 1`。 | |
| 内容: 商と余りの標準的な境界評価。 | |
| 証明: `Nat.div_eq_iff` をそのまま使う。 | |
| 役割: `floorProd_pred_div_eq` の前半境界を与える。 | |
| -/ | |
| private lemma floorProd_div_bounds | |
| (r a : Nat) (hApos : 0 < a) : | |
| let k := r / a | |
| k * a ≤ r ∧ r ≤ k * a + a - 1 := by | |
| simpa only [Nat.mul_comm] using (Nat.div_eq_iff hApos).1 rfl | |
| /-- | |
| 入力/前提: `x = a * n - r`、`0 < x`、`k * a ≤ r`。 | |
| 主張: `k < n`。 | |
| 内容: `r` の下界と `x` の正性から商 index が範囲内に入ることを示す。 | |
| 証明: `r < a * n` を経由して `k * a < n * a` に持ち込む。 | |
| 役割: `floorProd_pred_div_eq` で `n - k - 1` を正しく扱う前提に使う。 | |
| -/ | |
| private lemma floorProd_div_index_lt | |
| (n a k r x : Nat) (_hApos : 0 < a) (hx_pos : 0 < x) | |
| (hxr : x = a * n - r) (hk_lo : k * a ≤ r) : | |
| k < n := by | |
| have hr_lt_an : r < a * n := by | |
| have : 0 < a * n - r := by simpa only [hxr] using hx_pos | |
| exact Nat.sub_pos_iff_lt.mp this | |
| exact Nat.lt_of_mul_lt_mul_right <| | |
| lt_of_le_of_lt hk_lo (by simpa only [Nat.mul_comm] using hr_lt_an) | |
| /-- | |
| 入力/前提: `x = a * n - r`、`0 < x`、`k * a ≤ r ≤ k * a + a - 1`。 | |
| 主張: `(x - 1) / a = n - k - 1`。 | |
| 内容: `floorProd` の指数差を 1 回の除算式に橋渡しする等式。 | |
| 証明: 商余り境界を使って `x - 1` の商を直接計算する。 | |
| 役割: `floorProd_exponent_bridge` の中核変形。 | |
| -/ | |
| private lemma floorProd_pred_div_eq | |
| (n a k r x : Nat) (hApos : 0 < a) (hx_pos : 0 < x) | |
| (hxr : x = a * n - r) (hk_lo : k * a ≤ r) (hk_hi : r ≤ k * a + a - 1) : | |
| (x - 1) / a = n - k - 1 := by | |
| have hk_lt_n : k < n := floorProd_div_index_lt n a k r x hApos hx_pos hxr hk_lo | |
| 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) | |
| have : r < k * a + a := lt_of_le_of_lt hk_hi hpred_lt | |
| simpa only [Nat.succ_mul, Nat.add_comm, Nat.add_left_comm, Nat.add_assoc] using this | |
| have hr_lt_an : r < a * n := by | |
| have : 0 < a * n - r := by simpa only [hxr] using hx_pos | |
| exact Nat.sub_pos_iff_lt.mp this | |
| 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 [hxr] | |
| exact Nat.le_pred_of_lt hx_gt | |
| · 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 := hxr | |
| _ ≤ a * n - (k * a) := hsub_le | |
| _ = (n - k) * a := hright_eq | |
| have ht_lt_x : x - 1 < x := by | |
| exact Nat.sub_lt hx_pos (Nat.succ_pos 0) | |
| have ht_lt : x - 1 < (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' : x - 1 < (n - k - 1) * a + a := by | |
| simpa only [hmul_succ] using ht_lt | |
| exact Nat.le_pred_of_lt ht_lt' | |
| /-- | |
| 入力/前提: `m>0`, `0<a<m`, `0≤b<m`, `m ≤ a*n+b`。 | |
| 主張: floor_prod の while 更新で使う指数 `n-d` は仕様側の `⌊(yMax mod m)/a⌋` と一致。 | |
| 内容: 実装側 `suf` 更新式と仕様側第2分岐の指数を同一視する橋渡し補題。 | |
| 証明: `y=a*n+b`, `c=y/m`, `r=y%m`, `k=r/a` とおき、商剰余分解と不等式比較で `n-d=k` を導く。 | |
| 役割: `floorProdLoop_spec_invariant` の `c'≠0` 分岐を閉じる算術コア。 | |
| -/ | |
| private 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 | |
| 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 | |
| simpa only [c, y] using | |
| FloorProd.Internal.floorProd_div_pos_of_ge y m hM (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_bounds : k * a ≤ r ∧ r ≤ k * a + a - 1 := by | |
| simpa only [k] using floorProd_div_bounds r a hApos | |
| rcases hk_bounds with ⟨hk_lo, hk_hi⟩ | |
| have hk_lt_n : k < n := floorProd_div_index_lt n a k r x hApos hx_pos hmc_sub hk_lo | |
| have hq : t / a = n - k - 1 := by | |
| simpa only [t] using floorProd_pred_div_eq n a k r x hApos hx_pos hmc_sub hk_lo hk_hi | |
| 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] | |
| /-- | |
| 入力/前提: `((a % m) * n + (b % m)) / m ≠ 0`。 | |
| 主張: `0 < a % m`。 | |
| 内容: 再帰分岐では次の傾きが正になることを示す。 | |
| 証明: `a % m = 0` なら商が 0 になる補題の対偶を使う。 | |
| 役割: `floorProdLoop_spec_invariant_step_case` の再帰前提を供給する。 | |
| -/ | |
| private lemma floorProd_aMod_pos_of_cprime_ne_zero | |
| (n m a b : Nat) (hM : 0 < m) | |
| (hc0 : ((a % m) * n + (b % m)) / m ≠ 0) : | |
| 0 < a % m := by | |
| by_contra hNotPos | |
| have ha0 : a % m = 0 := Nat.eq_zero_of_not_pos hNotPos | |
| exact hc0 (floorProd_cprime_zero_of_aModZero n m a b hM ha0) | |
| /-- | |
| 入力/前提: `c' = (a * n + b) / m ≠ 0`。 | |
| 主張: `m ≤ a * n + b`。 | |
| 内容: 再帰分岐では高さが少なくとも 1 回は `m` を跨ぐ。 | |
| 証明: `a * n + b < m` なら商が 0 になることの対偶を使う。 | |
| 役割: `floorProdLoop_spec_invariant_step_case` で指数を橋渡しする。 | |
| -/ | |
| private lemma floorProd_yMax_ge_of_cprime_ne_zero | |
| (n m a b : Nat) (_hM : 0 < m) (hc0 : (a * n + b) / m ≠ 0) : | |
| m ≤ a * n + b := by | |
| exact Nat.le_of_not_gt (fun hlt => hc0 (Nat.div_eq_of_lt hlt)) | |
| /-- | |
| 入力/前提: `((st.a % st.m) * st.n + (st.b % st.m)) / st.m ≠ 0`。 | |
| 主張: 再帰分岐で使う正規化済み係数 `a' = st.a % st.m`, `b' = st.b % st.m` | |
| は `a' < st.m`, `b' < st.m`, `0 < a'`, `st.m ≤ a' * st.n + b'` を満たす。 | |
| 内容: `mod_lt` と、`c' ≠ 0` から従う既存補題をまとめたパッケージ。 | |
| 証明: 各成分を既存補題から順に構成する。 | |
| 役割: `floorProdLoop_spec_invariant_step_case` の冒頭の前提生成をまとめる。 | |
| -/ | |
| private lemma floorProd_step_bounds_of_cprime_ne_zero | |
| {α : Type _} [Monoid α] | |
| (st : LoopState α) (hM : 0 < st.m) | |
| (hc0 : ((st.a % st.m) * st.n + (st.b % st.m)) / st.m ≠ 0) : | |
| st.a % st.m < st.m | |
| ∧ st.b % st.m < st.m | |
| ∧ 0 < st.a % st.m | |
| ∧ st.m ≤ (st.a % st.m) * st.n + st.b % st.m := by | |
| refine ⟨Nat.mod_lt st.a hM, Nat.mod_lt st.b hM, ?_, ?_⟩ | |
| · exact floorProd_aMod_pos_of_cprime_ne_zero st.n st.m st.a st.b hM hc0 | |
| · exact floorProd_yMax_ge_of_cprime_ne_zero st.n st.m (st.a % st.m) (st.b % st.m) hM hc0 | |
| /-- | |
| 入力/前提: `Fuel.euclidN (fuel + 1) a m` が停止している。 | |
| 主張: 1 段進んだ後の Euclid 問題 `Fuel.euclidN fuel m (a % m)` も停止している。 | |
| 内容: Euclid 側の fuel 条件を再帰先へ 1 ステップ移す補題。 | |
| 証明: `Fuel.Internal.euclidN_succ` を `simp` で展開する。 | |
| 役割: `floorProdLoop_spec_invariant_step_case` で帰納法を適用する前提に使う。 | |
| -/ | |
| private lemma floorProd_fuel_tail | |
| (fuel a m : Nat) (hM : 0 < m) | |
| (hFuel : (Fuel.euclidN (fuel + 1) a m).2 = 0) : | |
| (Fuel.euclidN fuel m (a % m)).2 = 0 := by | |
| simpa only [Fuel.Internal.euclidN_succ, Fuel.Internal.euclid_step, Nat.ne_of_gt hM, | |
| ↓reduceDIte] using hFuel | |
| /-- | |
| 入力/前提: `q = st.b / st.m`, `x' = st.x * st.y ^ (st.a / st.m)` と停止判定 `c' = 0`。 | |
| 主張: `floorProdLoop (fuel + 1)` の実装側は停止枝の形 | |
| `(st.pre * st.y ^ q) * x' ^ st.n * st.suf` に一致する。 | |
| 内容: ループ本体を 1 回展開して停止枝を読む。 | |
| 証明: 定義展開と `simp` による。 | |
| 役割: `floorProdLoop_spec_invariant_stop_case` の実装側整理を分離する。 | |
| -/ | |
| private lemma floorProdLoop_stop_main | |
| {α : Type _} [Monoid α] | |
| (fuel : Nat) (st : LoopState α) | |
| (q : Nat) (x' : α) | |
| (hq : q = st.b / st.m) (hx' : x' = st.x * st.y ^ (st.a / st.m)) | |
| (hc0 : ((st.a % st.m) * st.n + (st.b % st.m)) / st.m = 0) : | |
| Impl.floorProdLoop (fuel + 1) st = (st.pre * st.y ^ q) * x' ^ st.n * st.suf := by | |
| subst q x' | |
| simp only [Impl.floorProdLoop, hc0, ↓reduceIte] | |
| /-- | |
| 入力/前提: `c' = 0`。 | |
| 主張: 実装 `floorProdLoop (fuel + 1)` は停止枝の閉形式 | |
| `(st.pre * st.y ^ (st.b / st.m)) * (st.x * st.y ^ (st.a / st.m)) ^ st.n * st.suf` | |
| に一致する。 | |
| 内容: `floorProdLoop_stop_main` の特殊化版。 | |
| 証明: 既存 helper の直接適用。 | |
| 役割: `floorProdLoop_spec_invariant_stop_case` から局所 `set` を除く。 | |
| -/ | |
| private lemma floorProdLoop_stop_of_cprime_zero | |
| {α : Type _} [Monoid α] | |
| (fuel : Nat) (st : LoopState α) | |
| (hc0 : ((st.a % st.m) * st.n + (st.b % st.m)) / st.m = 0) : | |
| Impl.floorProdLoop (fuel + 1) st = | |
| (st.pre * st.y ^ (st.b / st.m)) * (st.x * st.y ^ (st.a / st.m)) ^ st.n * st.suf := by | |
| exact floorProdLoop_stop_main fuel st (st.b / st.m) (st.x * st.y ^ (st.a / st.m)) rfl rfl hc0 | |
| /-- | |
| 目的: `best` が有効なときに束ねて保持する情報を定義する。 | |
| フィールド: `best, dx, arg`。 | |
| 不変条件: `dx` は `X` 個数、`arg` は最大達成の最小添字を表す。 | |
| 役割: `MwfElem.info?` の `some` 側のペイロード。 | |
| -/ | |
| private 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 化。 | |
| -/ | |
| private structure mwfElem where | |
| sum : Int | |
| info? : Option BestInfo := none | |
| deriving Repr, DecidableEq | |
| /-- | |
| 目的: `MwfElem` の単位元を定義する。 | |
| 定義: `sum=0, info?=none`。 | |
| 入力/前提: なし。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: `MwfElem` モノイドの単位元。 | |
| -/ | |
| private def MwfElemOne : mwfElem := | |
| { sum := 0, info? := none } | |
| /-- | |
| 目的: `MwfElem` の積(連結合成)を定義する。 | |
| 定義: Python 実装の `__mul__` 更新式をそのまま移植する。 | |
| 入力/前提: `lhs rhs : MwfElem`。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: floor_prod で prefix 最大と最小 argmax を合成する核。 | |
| -/ | |
| private 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 } } | |
| /-- | |
| 目的: `mwfElem` の単位元インスタンス。 | |
| 定義: `1` を `MwfElemOne` として解釈する。 | |
| 役割: `pow` と monoid 構造の基礎に使う。 | |
| -/ | |
| instance : One mwfElem := ⟨MwfElemOne⟩ | |
| /-- | |
| 目的: `mwfElem` の積インスタンス。 | |
| 定義: `(*)` を `mwfElemMul` として解釈する。 | |
| 役割: `floorProd` の積構造を Lean の演算子で扱えるようにする。 | |
| -/ | |
| instance : Mul mwfElem := ⟨mwfElemMul⟩ | |
| /-- | |
| 入力/前提: `u : MwfElem`。 | |
| 主張: `1 * u = u`。 | |
| 内容: `MwfElem` の左単位律。 | |
| 証明: `u` と内部 `info?` を場合分けし、`mwfElemMul` の定義展開を `simp` で閉じる。 | |
| 役割: `MwfElem` モノイド公理の一部。 | |
| -/ | |
| private theorem MwfElem_one_mul (u : mwfElem) : 1 * u = u := by | |
| rcases u with ⟨s, info⟩ | |
| cases info with | |
| | none => | |
| simpa using | |
| (by | |
| simp [mwfElemMul, MwfElemOne] : | |
| mwfElemMul MwfElemOne { sum := s, info? := none } = | |
| { sum := s, info? := none }) | |
| | some info => | |
| simpa using | |
| (by | |
| simp [mwfElemMul, MwfElemOne] : | |
| mwfElemMul MwfElemOne { sum := s, info? := some info } = | |
| { sum := s, info? := some info }) | |
| /-- | |
| 入力/前提: `u : MwfElem`。 | |
| 主張: `u * 1 = u`。 | |
| 内容: `MwfElem` の右単位律。 | |
| 証明: `u` と内部 `info?` を場合分けし、`mwfElemMul` の定義展開を `simp` で閉じる。 | |
| 役割: `MwfElem` モノイド公理の一部。 | |
| -/ | |
| private theorem MwfElem_mul_one (u : mwfElem) : u * 1 = u := by | |
| rcases u with ⟨s, info⟩ | |
| cases info with | |
| | none => | |
| simpa using | |
| (by | |
| simp [mwfElemMul, MwfElemOne] : | |
| mwfElemMul { sum := s, info? := none } MwfElemOne = | |
| { sum := s, info? := none }) | |
| | some info => | |
| simpa using | |
| (by | |
| simp [mwfElemMul, MwfElemOne] : | |
| mwfElemMul { sum := s, info? := some info } MwfElemOne = | |
| { sum := s, info? := some info }) | |
| /-- | |
| 目的: 2 つの score 候補から大きい方を選ぶ。 | |
| 定義: 第 1 成分 `best` を比較し、優位な組を返す。 | |
| 入力/前提: `p q : Int × Nat`。 | |
| 出力: より良い score を表す組。 | |
| 役割: `mwfElemMul` の `info?` 更新を抽象化する。 | |
| -/ | |
| private def MwfChooseScore (p q : Int × Nat) : Int × Nat := | |
| if p.1 < q.1 then q else p | |
| /-- | |
| 入力/前提: 2 つの score 候補 `p q` と `q.1 ≤ p.1`。 | |
| 主張: `MwfChooseScore p q` は左候補 `p` を返す。 | |
| 内容: 第 1 成分の比較で左が右以上なら左が採用される。 | |
| 証明: 定義展開後、`p.1 < q.1` が矛盾することを示す。 | |
| 役割: `mwfElem` 冪補題で比較分岐を直接展開せずに済ませる。 | |
| -/ | |
| private lemma MwfChooseScore_eq_left {p q : Int × Nat} (h : q.1 ≤ p.1) : | |
| MwfChooseScore p q = p := by | |
| simp [MwfChooseScore, not_lt_of_ge h] | |
| /-- | |
| 入力/前提: 2 つの score 候補 `p q` と `p.1 < q.1`。 | |
| 主張: `MwfChooseScore p q` は右候補 `q` を返す。 | |
| 内容: 第 1 成分の比較で右が左より大きければ右が採用される。 | |
| 証明: 定義展開して比較条件をそのまま適用する。 | |
| 役割: `mwfElem` 冪補題で比較分岐を直接展開せずに済ませる。 | |
| -/ | |
| private lemma MwfChooseScore_eq_right {p q : Int × Nat} (h : p.1 < q.1) : | |
| MwfChooseScore p q = q := by | |
| simp [MwfChooseScore, h] | |
| /-- | |
| 目的: score に prefix 和と位置ずれを加える。 | |
| 定義: 第 1 成分に `s`、第 2 成分に `k` を足す。 | |
| 入力/前提: シフト量 `s k` と score `p`。 | |
| 出力: シフト後の score。 | |
| 役割: 右側要素を左側 sum 分だけ平行移動する。 | |
| -/ | |
| private def MwfShiftScore (s : Int) (k : Nat) (p : Int × Nat) : Int × Nat := | |
| (s + p.1, k + p.2) | |
| /-- | |
| 目的: `BestInfo` を score 表現へ写す。 | |
| 定義: `(best, arg)` の組を取り出す。 | |
| 入力/前提: `BestInfo`。 | |
| 出力: 比較用の score。 | |
| 役割: `MwfChooseScore` と `MwfShiftScore` の入力に合わせる。 | |
| -/ | |
| private def MwfInfoScore (i : BestInfo) : Int × Nat := | |
| (i.best, i.arg) | |
| /-- | |
| 目的: score から `BestInfo` を再構成する。 | |
| 定義: 固定した `dx` と score の 2 成分を束ねる。 | |
| 入力/前提: 区間長 `dx` と score `sc`。 | |
| 出力: 対応する `BestInfo`。 | |
| 役割: `mwfElemMul` の更新結果を `BestInfo` に戻す。 | |
| -/ | |
| private def MwfMkInfoFromScore (dx : Nat) (sc : Int × Nat) : BestInfo := | |
| { best := sc.1, dx := dx, arg := sc.2 } | |
| /-- | |
| 入力/前提: 3 つの score 候補。 | |
| 主張: `MwfChooseScore` は結合的。 | |
| 内容: 最大 score を選ぶ演算としての結合律。 | |
| 証明: 定義展開と整数比較の分岐を `omega` で整理する。 | |
| 役割: `MwfElemMul_assoc_info` の `some/some/some` 枝で score の結合を揃える。 | |
| -/ | |
| 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 | |
| /-- | |
| 入力/前提: シフト量 `s k` と 2 つの score 候補。 | |
| 主張: score の選択とシフトは可換。 | |
| 内容: 大小比較は両辺へ同じシフトを足しても保たれる。 | |
| 証明: 定義展開後の比較を `omega` で処理する。 | |
| 役割: `MwfElemMul` の結合律で右側候補を並べ替える。 | |
| -/ | |
| 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 | |
| /-- | |
| 入力/前提: 2 段のシフト量と score `p`。 | |
| 主張: `MwfShiftScore` の 2 回適用は 1 回の合成シフトに等しい。 | |
| 内容: prefix 和と位置ずれの平行移動の合成則。 | |
| 証明: 成分ごとに足し算を整理する。 | |
| 役割: `MwfElemMul` の結合律でシフトの入れ子を潰す。 | |
| -/ | |
| 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 | |
| /-- | |
| 入力/前提: 左シフト `(s1, k1)`、追加シフト `(s2, k2)`、2 つの score `p q`。 | |
| 主張: 左側候補を平行移動して比較する操作は、右側候補の追加シフトを吸収したうえで | |
| 先に `MwfChooseScore` を取り、最後に左シフトする形へまとめられる。 | |
| 内容: `MwfShiftScore_comp` と `MwfChooseScore_shift` の合成版。 | |
| 証明: 右側候補の 2 段シフトを 1 回にまとめ、選択とシフトの可換性を適用する。 | |
| 役割: `MwfElemMul_assoc_info` の `none/some/some` 枝で score 計算を圧縮する。 | |
| -/ | |
| private lemma MwfChooseScore_shift_comp | |
| (s1 s2 : Int) (k1 k2 : Nat) (p q : Int × Nat) : | |
| MwfChooseScore (MwfShiftScore s1 k1 p) (MwfShiftScore (s1 + s2) (k1 + k2) q) = | |
| MwfShiftScore s1 k1 (MwfChooseScore p (MwfShiftScore s2 k2 q)) := by | |
| rw [← MwfShiftScore_comp s1 s2 k1 k2 q] | |
| simpa using (MwfChooseScore_shift s1 k1 p (MwfShiftScore s2 k2 q)).symm | |
| /-- | |
| 入力/前提: `info? = some` の 2 要素。 | |
| 主張: `mwfElemMul` の結果は `MwfChooseScore` と `MwfShiftScore` で書ける。 | |
| 内容: `info` 付き同士の積の explicit formula。 | |
| 証明: `mwfElemMul` を展開し、大小比較の 2 分岐を整理する。 | |
| 役割: 各 associativity 補題の共通部品になる。 | |
| -/ | |
| 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 := le_of_not_gt hlt | |
| simp only [hlt, hge, ↓reduceIte] | |
| /-- | |
| 入力/前提: 左要素は `info? = none`、右要素は `info? = some r`。 | |
| 主張: `mwfElemMul` の結果は `r` を左シフトした `some` 情報を持つ。 | |
| 内容: 片側だけ情報を持つ積の explicit formula。 | |
| 証明: `mwfElemMul` を定義展開して `simp` で示す。 | |
| 役割: `MwfElemMul_assoc_info` で片側だけ `some` を持つ内側積を展開する。 | |
| -/ | |
| private lemma MwfElemMul_none_some | |
| (s1 s2 : Int) (r : BestInfo) : | |
| mwfElemMul { sum := s1 } { sum := s2, info? := some r } = | |
| { sum := s1 + s2 | |
| info? := some (MwfMkInfoFromScore r.dx (MwfShiftScore s1 0 (MwfInfoScore r))) } := by | |
| simp only [mwfElemMul, MwfMkInfoFromScore, MwfShiftScore, MwfInfoScore, zero_add] | |
| /-- | |
| 入力/前提: 左要素は `info? = some l`、右要素は `info? = none`。 | |
| 主張: `mwfElemMul` の結果は情報 `l` を保ったまま和だけが加算される。 | |
| 内容: 片側だけ情報を持つ積のもう一方の explicit formula。 | |
| 証明: `mwfElemMul` を定義展開して `simp` で示す。 | |
| 役割: `MwfElemMul_assoc_info` で右側が `none` の内側積を展開する。 | |
| -/ | |
| private lemma MwfElemMul_some_none | |
| (s1 s2 : Int) (l : BestInfo) : | |
| mwfElemMul { sum := s1, info? := some l } { sum := s2 } = | |
| { sum := s1 + s2, info? := some l } := by | |
| simp only [mwfElemMul] | |
| /-- | |
| 入力/前提: 両方とも `info? = none` の `MwfElem`。 | |
| 主張: その積は和だけを足し、`info? = none` を保つ。 | |
| 内容: `none/none` ケースの explicit formula。 | |
| 証明: `mwfElemMul` を定義展開して `simp` で示す。 | |
| 役割: trivial な associativity 分岐と `mwfElem` 冪計算を簡潔化する。 | |
| -/ | |
| private lemma MwfElemMul_none_none | |
| (s1 s2 : Int) : | |
| mwfElemMul { sum := s1 } { sum := s2 } = { sum := s1 + s2 } := by | |
| simp only [mwfElemMul] | |
| /-- | |
| 入力/前提: 3 要素の `sum` とそれぞれの `info?`。 | |
| 主張: `info?` の 8 通りすべてで `mwfElemMul` は結合的。 | |
| 内容: `MwfElem_mul_assoc` 用の場合分けを 1 か所に集約する。 | |
| 証明: `Option BestInfo` の 8 通りを直接処理し、`MwfElemMul_*` の explicit formula と | |
| shift/score 補題で各枝を同一化する。 | |
| 役割: 本体の `cases` と単発 helper を増やさずに associativity を支える。 | |
| -/ | |
| private lemma MwfElemMul_assoc_info | |
| (su sv sw : Int) : | |
| ∀ iu iv iw : Option BestInfo, | |
| mwfElemMul (mwfElemMul { sum := su, info? := iu } { sum := sv, info? := iv }) | |
| { sum := sw, info? := iw } = | |
| mwfElemMul { sum := su, info? := iu } | |
| (mwfElemMul { sum := sv, info? := iv } { sum := sw, info? := iw }) | |
| | none, none, none => by | |
| repeat rw [MwfElemMul_none_none] | |
| simp only [mwfElem.mk.injEq, and_true] | |
| omega | |
| | none, none, some w => by | |
| rw [MwfElemMul_none_none] | |
| repeat rw [MwfElemMul_none_some] | |
| simp [add_assoc, MwfMkInfoFromScore, MwfInfoScore, MwfShiftScore_comp] | |
| | none, some v, none => by | |
| rw [MwfElemMul_none_some su sv v] | |
| repeat rw [MwfElemMul_some_none] | |
| rw [MwfElemMul_none_some] | |
| simp [add_assoc, MwfMkInfoFromScore, MwfInfoScore] | |
| | none, some v, some w => by | |
| rw [MwfElemMul_none_some su sv v, MwfElemMul_some_some sv sw v w] | |
| 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 | |
| simpa only [zero_add] using | |
| MwfChooseScore_shift_comp su sv 0 v.dx (MwfInfoScore v) (MwfInfoScore w) | |
| refine ⟨by omega, ?_, ?_⟩ | |
| · exact congrArg Prod.fst hmain | |
| · simpa only [MwfShiftScore, zero_add] using congrArg Prod.snd hmain | |
| | some u, none, none => by | |
| rw [MwfElemMul_some_none su sv u] | |
| rw [MwfElemMul_none_none] | |
| repeat rw [MwfElemMul_some_none] | |
| simp [add_assoc] | |
| | some u, none, some w => by | |
| rw [MwfElemMul_some_none su sv u, MwfElemMul_none_some sv sw w] | |
| repeat rw [MwfElemMul_some_some] | |
| simp only [MwfMkInfoFromScore, MwfInfoScore, Prod.mk.eta, MwfShiftScore_comp, | |
| add_zero, mwfElem.mk.injEq, and_true] | |
| omega | |
| | some u, some v, none => by | |
| rw [MwfElemMul_some_some su sv u v, MwfElemMul_some_none sv sw v] | |
| repeat rw [MwfElemMul_some_some] | |
| simp only [mwfElemMul, MwfMkInfoFromScore, MwfInfoScore, mwfElem.mk.injEq, | |
| and_true] | |
| omega | |
| | some u, some v, some w => by | |
| rw [MwfElemMul_some_some su sv u v, MwfElemMul_some_some sv sw v w] | |
| 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` をモノイドに昇格する主要補題。 | |
| 証明: `u,v,w` と `info?` の全場合分け後、補助補題と `omega` で各枝を同一化する。 | |
| 役割: `floorProd` を `MwfElem` に適用する前提。 | |
| -/ | |
| private theorem MwfElem_mul_assoc (u v w : mwfElem) : | |
| (u * v) * w = u * (v * w) := by | |
| rcases u with ⟨su, iu⟩ | |
| rcases v with ⟨sv, iv⟩ | |
| rcases w with ⟨sw, iw⟩ | |
| simpa using MwfElemMul_assoc_info su sv sw iu iv iw | |
| /-- | |
| 目的: `mwfElem` に monoid 構造を入れる。 | |
| 定義: 単位元は `1`、積は `(*)`、公理は既証明の補題で与える。 | |
| 役割: `floorProd` 実装で一般 monoid 上の指数法則を使うための基盤。 | |
| -/ | |
| 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 上で表し、正しさ定理で検証する対象。 | |
| -/ | |
| private 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 } } | |
| /-- | |
| 入力/前提: 整数 `s` と自然数 `k`。 | |
| 主張: `s * succ k + s = s * succ (succ k)`。 | |
| 内容: 累積和の閉形式で使う整数版の 1 ステップ補題。 | |
| 証明: 整数環の演算を展開して整理する。 | |
| 役割: `mwfElem` の冪の帰納計算を短くする。 | |
| -/ | |
| 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] | |
| /-- | |
| 入力/前提: 自然数 `d k`。 | |
| 主張: `d * succ k + d = d * succ (succ k)`。 | |
| 内容: `dx` 更新で使う自然数版の 1 ステップ補題。 | |
| 証明: `Nat.mul_succ` を並べ替える。 | |
| 役割: `mwfElem` の冪で `dx` を追跡する。 | |
| -/ | |
| 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 | |
| /-- | |
| 入力/前提: `info? = none` の閉形式状態と 1 個の元 `{sum := s}`。 | |
| 主張: それらの積は次の閉形式状態に一致する。 | |
| 内容: `mwfElem_pow_none_succ` の帰納ステップを切り出した補題。 | |
| 証明: `mwfElemMul` を展開し、和の更新を `int_mul_succ` で整理する。 | |
| 役割: `mwfElem_pow_none_succ` の本体を短く保つ。 | |
| -/ | |
| private lemma mwfElem_pow_none_step (s : Int) (k : Nat) : | |
| ({ sum := s * (Nat.succ k), info? := none } : mwfElem) * { sum := s, info? := none } = | |
| { 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 } | |
| rw [MwfElemMul_none_none] | |
| simp only [mwfElem.mk.injEq, and_true] | |
| simpa using int_mul_succ s k | |
| /-- | |
| 入力/前提: `s ≤ 0` の閉形式状態と 1 個の `some info` 要素。 | |
| 主張: それらの積は非正ケースの次の閉形式状態に一致する。 | |
| 内容: `best` は据え置きで、`sum` と `dx` だけが 1 段伸びる。 | |
| 証明: 比較条件が常に左枝になることを示して `mwfElemMul` を簡約する。 | |
| 役割: `mwfElem_pow_some_nonpos_succ` の帰納ステップを分離する。 | |
| -/ | |
| private lemma mwfElem_pow_some_nonpos_step (s : Int) (info : BestInfo) (k : Nat) (hS : s ≤ 0) : | |
| ({ sum := s * (Nat.succ k) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } : mwfElem) * { 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 } } := by | |
| have hMulNonPos : s * (Nat.succ k) ≤ 0 := | |
| mul_nonpos_of_nonpos_of_nonneg hS (Int.natCast_nonneg _) | |
| have hge : | |
| info.best ≥ s * (Nat.succ k) + info.best := by | |
| nlinarith [hMulNonPos] | |
| have hge' : | |
| info.best ≥ s * ((k : Int) + 1) + info.best := by | |
| simpa only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using hge | |
| have hchoose : | |
| MwfChooseScore | |
| (MwfInfoScore | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg }) | |
| (MwfShiftScore (s * (Nat.succ k)) (info.dx * (Nat.succ k)) (MwfInfoScore info)) = | |
| MwfInfoScore | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } := by | |
| apply MwfChooseScore_eq_left | |
| simpa only [MwfInfoScore, MwfShiftScore, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] | |
| using hge' | |
| 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 } } | |
| rw [MwfElemMul_some_some] | |
| rw [hchoose] | |
| simp only [MwfMkInfoFromScore, MwfInfoScore, int_mul_succ, nat_mul_succ] | |
| /-- | |
| 入力/前提: `0 < s` の閉形式状態と 1 個の `some info` 要素。 | |
| 主張: それらの積は正ケースの次の閉形式状態に一致する。 | |
| 内容: 右枝が常に優勢になり、`best` と `arg` も 1 段先へ進む。 | |
| 証明: 比較条件が常に右枝になることを示して `mwfElemMul` を簡約する。 | |
| 役割: `mwfElem_pow_some_pos_succ` の帰納ステップを分離する。 | |
| -/ | |
| private lemma mwfElem_pow_some_pos_step (s : Int) (info : BestInfo) (k : Nat) (hS : 0 < s) : | |
| ({ 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) * { 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 } } := 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) := | |
| 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 hchoose : | |
| MwfChooseScore | |
| (MwfInfoScore | |
| { best := s * k + info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.dx * k + info.arg }) | |
| (MwfShiftScore (s * (Nat.succ k)) (info.dx * (Nat.succ k)) (MwfInfoScore info)) = | |
| MwfShiftScore (s * (Nat.succ k)) (info.dx * (Nat.succ k)) (MwfInfoScore info) := by | |
| apply MwfChooseScore_eq_right | |
| simpa only [MwfInfoScore, MwfShiftScore, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] | |
| using hlt | |
| 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 } } | |
| rw [MwfElemMul_some_some] | |
| rw [hchoose] | |
| simp only [MwfMkInfoFromScore, MwfInfoScore, MwfShiftScore, int_mul_succ, nat_mul_succ] | |
| /-- | |
| 入力/前提: `z : mwfElem`、閉形式候補 `F : Nat → mwfElem`。 | |
| 主張: `F 0 = z` かつ `F k * z = F (k+1)` なら、`z^(k+1) = F k`。 | |
| 内容: `pow_succ` に沿った共通の帰納骨格を抽象化する。 | |
| 証明: 基底は `pow_one`、帰納段は `pow_succ` と `hstep` を連結する。 | |
| 役割: `mwfElem_pow_*_succ` 3 本の重複した帰納パターンを吸収する。 | |
| -/ | |
| private lemma mwfElem_pow_succ_of_step | |
| (z : mwfElem) (F : Nat → mwfElem) | |
| (h0 : z = F 0) | |
| (hstep : ∀ k, F k * z = F (Nat.succ k)) : | |
| ∀ k, z ^ (Nat.succ k) = F k | |
| | 0 => by | |
| simpa only [pow_one] using h0 | |
| | k + 1 => by | |
| calc | |
| z ^ (Nat.succ (Nat.succ k)) = (z ^ (Nat.succ k)) * z := by | |
| simp only [pow_succ] | |
| _ = F k * z := by | |
| rw [mwfElem_pow_succ_of_step z F h0 hstep k] | |
| _ = F (Nat.succ k) := hstep k | |
| /-- | |
| 入力/前提: `info? = none` の要素 `{sum := s}`。 | |
| 主張: その `succ k` 乗は `{sum := s * succ k, info? := none}`。 | |
| 内容: 情報なし要素の冪の閉形式。 | |
| 証明: `pow` の帰納法で積を展開し、`int_mul_succ` を使う。 | |
| 役割: `mwfElemPowImpl_correct` の `none` ケースを処理する。 | |
| -/ | |
| private lemma mwfElem_pow_none_succ (s : Int) : | |
| ∀ k, ({ sum := s, info? := none } : mwfElem) ^ (Nat.succ k) = | |
| { sum := s * (Nat.succ k), info? := none } := | |
| mwfElem_pow_succ_of_step | |
| { sum := s, info? := none } | |
| (fun k => ({ sum := s * (Nat.succ k), info? := none } : mwfElem)) | |
| (by simp only [Nat.succ_eq_add_one, zero_add, Nat.cast_one, mul_one]) | |
| (fun k => mwfElem_pow_none_step s k) | |
| /-- | |
| 入力/前提: `s ≤ 0` と `info? = some info`。 | |
| 主張: その `succ k` 乗は `best` を固定しつつ `sum` と `dx` だけ線形に伸びる。 | |
| 内容: 非正の和では最良値が先頭要素から動かない場合の冪の閉形式。 | |
| 証明: `pow` の帰納法で、比較条件が常に同じ側を選ぶことを使う。 | |
| 役割: `mwfElemPowImpl_correct` の非正ケースを処理する。 | |
| -/ | |
| 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 } } := | |
| mwfElem_pow_succ_of_step | |
| { sum := s, info? := some info } | |
| (fun k => | |
| ({ sum := s * (Nat.succ k) | |
| info? := some | |
| { best := info.best | |
| dx := info.dx * (Nat.succ k) | |
| arg := info.arg } } : mwfElem)) | |
| (by simp only [Nat.succ_eq_add_one, zero_add, Nat.cast_one, mul_one]) | |
| (fun k => mwfElem_pow_some_nonpos_step s info k hS) | |
| /-- | |
| 入力/前提: `0 < s` と `info? = some info`。 | |
| 主張: その `succ k` 乗は `best` と `arg` も等差的に増える閉形式を持つ。 | |
| 内容: 正の和では右へ進むほど score が伸びる場合の冪の閉形式。 | |
| 証明: `pow` の帰納法で比較条件が常に右側を選ぶことを使う。 | |
| 役割: `mwfElemPowImpl_correct` の正ケースを処理する。 | |
| -/ | |
| 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 } } := | |
| mwfElem_pow_succ_of_step | |
| { sum := s, info? := some info } | |
| (fun 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)) | |
| (by | |
| simp only [Nat.succ_eq_add_one, zero_add, Nat.cast_one, mul_one, CharP.cast_eq_zero, | |
| mul_zero]) | |
| (fun k => mwfElem_pow_some_pos_step s info k hS) | |
| /-- | |
| 入力/前提: `sum = s`, `info? = some info` の `mwfElem` と `succ k`。 | |
| 主張: `mwfElemPowImpl` の `some` ケースはモノイド冪 `^(succ k)` と一致する。 | |
| 内容: `s > 0` と `s ≤ 0` の 2 分岐だけを処理する helper。 | |
| 証明: `mwfElem_pow_some_pos_succ` と `mwfElem_pow_some_nonpos_succ` に場合分けで還元する。 | |
| 役割: `mwfElemPowImpl_correct_succ` から符号分岐を切り離す。 | |
| -/ | |
| private lemma mwfElemPowImpl_correct_some_succ | |
| (s : Int) (info : BestInfo) (k : Nat) : | |
| mwfElemPowImpl ({ sum := s, info? := some info } : mwfElem) (Nat.succ k) = | |
| ({ sum := s, info? := some info } : mwfElem) ^ (Nat.succ k) := by | |
| 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 | |
| · 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 (le_of_not_gt hS) k).symm | |
| /-- | |
| 入力/前提: `sum = s`, `info? = none` の `mwfElem` と `succ k`。 | |
| 主張: `mwfElemPowImpl` の `none` ケースはモノイド冪 `^(succ k)` と一致する。 | |
| 内容: 情報なし要素の閉形式 `mwfElem_pow_none_succ` への薄い wrapper。 | |
| 証明: `mwfElem_pow_none_succ` をそのまま実装定義へ戻す。 | |
| 役割: `mwfElemPowImpl_correct_succ` の `none` 分岐を対称化する。 | |
| -/ | |
| private lemma mwfElemPowImpl_correct_none_succ | |
| (s : Int) (k : Nat) : | |
| mwfElemPowImpl ({ sum := s, info? := none } : mwfElem) (Nat.succ k) = | |
| ({ sum := s, info? := none } : mwfElem) ^ (Nat.succ k) := by | |
| simpa only [mwfElemPowImpl, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one] using | |
| (mwfElem_pow_none_succ s k).symm | |
| /-- | |
| 入力/前提: `sum = s`, `info? = info?` の `mwfElem` と `succ k`。 | |
| 主張: `mwfElemPowImpl` の `succ` ケースはモノイド冪 `^(succ k)` と一致する。 | |
| 内容: `info?` の有無と `s` の符号ごとに既存の閉形式補題へ還元する。 | |
| 証明: `none` / `some` を場合分けし、`some` 側はさらに `s > 0` で分岐して | |
| `mwfElem_pow_none_succ` / `mwfElem_pow_some_nonpos_succ` / `mwfElem_pow_some_pos_succ` | |
| を適用する。 | |
| 役割: `mwfElemPowImpl_correct` から `succ` ケースの詳細分岐を切り離す。 | |
| -/ | |
| private lemma mwfElemPowImpl_correct_succ | |
| (s : Int) (info? : Option BestInfo) (k : Nat) : | |
| mwfElemPowImpl ({ sum := s, info? := info? } : mwfElem) (Nat.succ k) = | |
| ({ sum := s, info? := info? } : mwfElem) ^ (Nat.succ k) := by | |
| cases info? with | |
| | none => | |
| simpa using mwfElemPowImpl_correct_none_succ s k | |
| | some info => | |
| simpa using mwfElemPowImpl_correct_some_succ s info 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__` 実装が数理仕様(モノイド冪)に正しいことの検証定理。 | |
| -/ | |
| private theorem mwfElemPowImpl_correct (z : mwfElem) (k : Nat) : | |
| mwfElemPowImpl z k = z ^ k := by | |
| rcases z with ⟨s, info?⟩ | |
| cases k with | |
| | zero => | |
| simp [mwfElemPowImpl] | |
| | succ k => | |
| simp [mwfElemPowImpl_correct_succ] | |
| /-- | |
| 目的: `X=(sum=a,info?=some(best=0,dx=1,arg=0))` を定義する。 | |
| 定義: `MwfElem` の初期要素 `X`。 | |
| 入力/前提: `a : Int`。 | |
| 出力: 型 `MwfElem` の値を返す。 | |
| 役割: sssec:mwf_floor_prod の写像で使う `x` 側モノイド要素。 | |
| -/ | |
| private 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` 側モノイド要素。 | |
| -/ | |
| private def mwfElemY (b : Int) : mwfElem := | |
| { sum := b, info? := none } | |
| end Internal | |
| /-- | |
| 目的: `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) : | |
| mwfWithArgResult := | |
| let nI := R - L | |
| let mI := M | |
| let qC := Spec.zfloorDiv C M hM | |
| let cI := Spec.zfloorMod C M hM | |
| let kI := C * L + D | |
| let qD := Spec.zfloorDiv kI M hM | |
| let dI := Spec.zfloorMod kI M hM | |
| let aI := A + B * qC | |
| let cst := A * L + B * qD | |
| let res : Internal.mwfElem := | |
| Impl.floorProd (Int.toNat nI) (Int.toNat mI) (Int.toNat cI) (Int.toNat dI) | |
| (Internal.mwfElemX aI) (Internal.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 | |
| namespace Correctness | |
| namespace Internal | |
| private lemma floorProdFormula_eq_pow_of_stop_normalized | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (x y : α) (hM : 0 < m) | |
| (_hA_lt : a < m) (hB_lt : b < m) | |
| (hStop : a * n + b < m) : | |
| FloorProd.Spec.floorProdFormula n m a b x y = x ^ n := by | |
| induction n with | |
| | zero => | |
| conv_lhs => unfold FloorProd.Spec.floorProdFormula | |
| simp [Nat.ne_of_gt hM, Nat.div_eq_of_lt hB_lt] | |
| | succ n ih => | |
| have hStopPrev : a * n + b < m := by | |
| have hmul_le : a * n ≤ a * (n + 1) := by | |
| exact Nat.mul_le_mul_left _ (Nat.le_succ n) | |
| have hle : a * n + b ≤ a * (n + 1) + b := | |
| Nat.add_le_add_right hmul_le _ | |
| exact lt_of_le_of_lt hle hStop | |
| have hqPrev : (a * n + b) / m = 0 := Nat.div_eq_of_lt hStopPrev | |
| have hqNext : (a * (n + 1) + b) / m = 0 := Nat.div_eq_of_lt hStop | |
| have hDelta : ((a * (n + 1) + b) / m) - ((a * n + b) / m) = 0 := by | |
| rw [hqNext, hqPrev] | |
| rw [FloorProd.Spec.floorProdFormula_succ, ih hStopPrev, hDelta, pow_succ] | |
| simp | |
| /-- | |
| 入力/前提: `0 < m`, `a < m` と、正規化後の 1 ステップで繰り上がりが起きない条件。 | |
| 主張: 商 `⌊(a*(i+1)+b)/m⌋` は前段 `⌊(a*i+b)/m⌋` と等しい。 | |
| 内容: 正規化後は 1 回で高さが 2 段以上増えないので、非繰り上がり時は商差 0。 | |
| 証明: `a*i+b = m*q + r` に分解し、`r+a < m` を用いて `Nat.div_eq_iff` で示す。 | |
| 役割: 再帰式の `n` 帰納で「末尾ブロックが `x` だけ」の場合を切り出す。 | |
| -/ | |
| private lemma floorProd_step_div_eq_of_lt | |
| (i m a b : Nat) (hM : 0 < m) (_hA_lt : a < m) | |
| (hNoCarry : (a * i + b) % m + a < m) : | |
| (a * (i + 1) + b) / m = (a * i + b) / m := by | |
| let q := (a * i + b) / m | |
| let r := (a * i + b) % m | |
| have hNoCarry' : r + a < m := by | |
| simpa only [r] using hNoCarry | |
| have hqr : a * i + b = m * q + r := by | |
| simpa only [q, r, Nat.add_comm] using (Nat.mod_add_div (a * i + b) m).symm | |
| have hy : a * (i + 1) + b = m * q + (r + a) := by | |
| calc | |
| a * (i + 1) + b = a * i + b + a := by ring | |
| _ = m * q + r + a := by rw [hqr] | |
| _ = m * q + (r + a) := by ac_rfl | |
| have hdiv : (a * (i + 1) + b) / m = q := by | |
| apply (Nat.div_eq_iff hM).2 | |
| constructor | |
| · simpa only [Nat.mul_comm, hy] using Nat.le_add_right (q * m) (r + a) | |
| · have hle0 : r + a ≤ m - 1 := Nat.le_pred_of_lt hNoCarry' | |
| have hle1 := Nat.add_le_add_left hle0 (q * m) | |
| rw [hy] | |
| have hle2 : m * q + (r + a) ≤ q * m + (m - 1) := by | |
| simpa [Nat.mul_comm] using hle1 | |
| have hle3 : q * m + (m - 1) ≤ q * m + m - 1 := by | |
| omega | |
| exact le_trans hle2 hle3 | |
| simpa only [q] using hdiv | |
| private lemma floorProd_step_mod_eq_of_lt | |
| (i m a b : Nat) (_hM : 0 < m) | |
| (hNoCarry : (a * i + b) % m + a < m) : | |
| (a * (i + 1) + b) % m = (a * i + b) % m + a := by | |
| let q := (a * i + b) / m | |
| let r := (a * i + b) % m | |
| have hNoCarry' : r + a < m := by | |
| simpa only [r] using hNoCarry | |
| have hqr : a * i + b = m * q + r := by | |
| simpa only [q, r, Nat.add_comm] using (Nat.mod_add_div (a * i + b) m).symm | |
| have hy : a * (i + 1) + b = m * q + (r + a) := by | |
| calc | |
| a * (i + 1) + b = a * i + b + a := by ring | |
| _ = m * q + r + a := by rw [hqr] | |
| _ = m * q + (r + a) := by ac_rfl | |
| calc | |
| (a * (i + 1) + b) % m = (m * q + (r + a)) % m := by rw [hy] | |
| _ = ((r + a) + m * q) % m := by ac_rfl | |
| _ = (r + a) % m := Nat.add_mul_mod_self_left _ _ _ | |
| _ = r + a := Nat.mod_eq_of_lt hNoCarry' | |
| _ = (a * i + b) % m + a := by simp [r, Nat.add_comm] | |
| private lemma floorProd_step_mod_div_eq_zero_of_le | |
| (i m a b : Nat) (hM : 0 < m) (hA_lt : a < m) | |
| (hCarry : m ≤ (a * i + b) % m + a) : | |
| ((a * (i + 1) + b) % m) / a = 0 := by | |
| let q := (a * i + b) / m | |
| let r := (a * i + b) % m | |
| have hCarry' : m ≤ r + a := by | |
| simpa only [r] using hCarry | |
| have hr_lt : r < m := by | |
| simp only [r] | |
| exact Nat.mod_lt _ hM | |
| have hqr : a * i + b = m * q + r := by | |
| simpa only [q, r, Nat.add_comm] using (Nat.mod_add_div (a * i + b) m).symm | |
| have hsplit : m * q + (r + a) = m * q + (r + a - m) + m := by | |
| calc | |
| m * q + (r + a) = m * q + ((r + a - m) + m) := by | |
| congr 1 | |
| exact (Nat.sub_eq_iff_eq_add hCarry').1 rfl | |
| _ = m * q + (r + a - m) + m := by ac_rfl | |
| have hnum : a * (i + 1) + b = m * (q + 1) + (r + a - m) := by | |
| calc | |
| a * (i + 1) + b = a * i + b + a := by ring | |
| _ = m * q + r + a := by rw [hqr] | |
| _ = m * q + (r + a) := by ac_rfl | |
| _ = m * q + (r + a - m) + m := hsplit | |
| _ = m * (q + 1) + (r + a - m) := by | |
| simp [Nat.mul_add, Nat.add_assoc, Nat.add_comm] | |
| rw [calc | |
| (a * (i + 1) + b) % m = (m * (q + 1) + (r + a - m)) % m := by rw [hnum] | |
| _ = ((r + a - m) + m * (q + 1)) % m := by ac_rfl | |
| _ = (r + a - m) % m := Nat.add_mul_mod_self_left _ _ _ | |
| _ = r + a - m := by | |
| have hrem_lt_a : r + a - m < a := by omega | |
| exact Nat.mod_eq_of_lt (lt_trans hrem_lt_a hA_lt) | |
| _ = (a * i + b) % m + a - m := by simp [r, Nat.add_comm]] | |
| have hr_lt : (a * i + b) % m < m := Nat.mod_lt _ hM | |
| have hrem_lt_a : (a * i + b) % m + a - m < a := by | |
| omega | |
| exact Nat.div_eq_of_lt hrem_lt_a | |
| private lemma floorProd_step_div_eq_one_of_lt_of_le | |
| (i m a b : Nat) (hM : 0 < m) (hA_lt : a < m) | |
| (hPrevLt : a * i + b < m) | |
| (hCarry : m ≤ (a * i + b) % m + a) : | |
| (a * (i + 1) + b) / m = 1 := by | |
| apply (Nat.div_eq_iff hM).2 | |
| constructor | |
| · calc | |
| 1 * m = m := by simp | |
| _ ≤ (a * i + b) + a := by simpa [Nat.mod_eq_of_lt hPrevLt] using hCarry | |
| _ = a * (i + 1) + b := by ring | |
| · have hUpper : a * (i + 1) + b < m + m := by | |
| calc | |
| a * (i + 1) + b = (a * i + b) + a := by ring | |
| _ < m + a := Nat.add_lt_add_right hPrevLt a | |
| _ < m + m := Nat.add_lt_add_left hA_lt m | |
| simpa using Nat.le_pred_of_lt hUpper | |
| /-- | |
| 入力/前提: `0 < m`, `a < m` と、末尾ステップで繰り上がりが起きない条件。 | |
| 主張: `floorProdFormula (n+1)` の末尾ブロックは `x` に簡約する。 | |
| 内容: 差分指数が 0 になる場合。 | |
| 証明: `floorProdFormula_succ` と商差 0 の補題を使う。 | |
| 役割: recurrence を `n` 帰納で証明するときの非繰り上がり枝。 | |
| -/ | |
| private lemma floorProdFormula_succ_of_no_carry | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (x y : α) (hM : 0 < m) (hA_lt : a < m) | |
| (hNoCarry : (a * n + b) % m + a < m) : | |
| FloorProd.Spec.floorProdFormula (n + 1) m a b x y = | |
| FloorProd.Spec.floorProdFormula n m a b x y * x := by | |
| simpa [floorProd_step_div_eq_of_lt n m a b hM hA_lt hNoCarry] using | |
| FloorProd.Spec.floorProdFormula_succ n m a b x y | |
| /-- | |
| 入力/前提: `0 < m`, `a < m` と、末尾ステップで繰り上がりが起きる条件。 | |
| 主張: `floorProdFormula (n+1)` の末尾ブロックは `x * y` に簡約する。 | |
| 内容: 差分指数が 1 になる場合。 | |
| 証明: `floorProdFormula_succ` と商差 1 の補題を使う。 | |
| 役割: recurrence を `n` 帰納で証明するときの繰り上がり枝。 | |
| -/ | |
| private lemma floorProdFormula_succ_of_carry | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (x y : α) (hM : 0 < m) (hA_lt : a < m) | |
| (hCarry : m ≤ (a * n + b) % m + a) : | |
| FloorProd.Spec.floorProdFormula (n + 1) m a b x y = | |
| FloorProd.Spec.floorProdFormula n m a b x y * (x * y) := by | |
| have hqCarry : (a * (n + 1) + b) / m = (a * n + b) / m + 1 := by | |
| let q := (a * n + b) / m | |
| let r := (a * n + b) % m | |
| have hCarry' : m ≤ r + a := by | |
| simpa only [r] using hCarry | |
| have hr_lt : r < m := by | |
| simp only [r] | |
| exact Nat.mod_lt _ hM | |
| have hsum_lt : r + a < m + m := Nat.add_lt_add hr_lt hA_lt | |
| have hqr : a * n + b = m * q + r := by | |
| simpa only [q, r, Nat.add_comm] using (Nat.mod_add_div (a * n + b) m).symm | |
| have hnum : a * (n + 1) + b = m * q + (r + a) := by | |
| calc | |
| a * (n + 1) + b = a * n + b + a := by ring | |
| _ = m * q + r + a := by rw [hqr] | |
| _ = m * q + (r + a) := by ac_rfl | |
| have hdiv : (a * (n + 1) + b) / m = q + 1 := by | |
| apply (Nat.div_eq_iff hM).2 | |
| constructor | |
| · have hle := Nat.add_le_add_left hCarry' (m * q) | |
| rw [hnum] | |
| calc | |
| (q + 1) * m = m * q + m := by ring | |
| _ ≤ m * q + (r + a) := hle | |
| · have hle0 : r + a ≤ m + m - 1 := Nat.le_pred_of_lt hsum_lt | |
| have hle1 := Nat.add_le_add_left hle0 (m * q) | |
| rw [hnum] | |
| calc | |
| m * q + (r + a) ≤ m * q + (m + m - 1) := hle1 | |
| _ = m * q + m + m - 1 := by omega | |
| _ = (q + 1) * m + m - 1 := by | |
| rw [Nat.add_mul, one_mul] | |
| ac_rfl | |
| simpa only [q] using hdiv | |
| simpa [hqCarry] using | |
| FloorProd.Spec.floorProdFormula_succ n m a b x y | |
| private lemma floorProd_transposed_next_num_eq | |
| (n m a b c r : Nat) | |
| (hy : a * n + b = m * c + r) | |
| (hB_lt : b < m) (hr_lt : r < m) : | |
| m * c + (m - b - 1 + a) = (m - r - 1) + a * (n + 1) := by | |
| have hb1 : b + 1 ≤ m := Nat.succ_le_of_lt hB_lt | |
| have hsubb : m - b - 1 = m - (b + 1) := by omega | |
| have hsubr : m - r - 1 = m - (r + 1) := by omega | |
| calc | |
| m * c + (m - b - 1 + a) | |
| = m * c + (m - (b + 1)) + a := by | |
| rw [hsubb] | |
| ac_rfl | |
| _ = (m * c + m - (b + 1)) + a := by | |
| rw [Nat.add_sub_assoc hb1] | |
| _ = (a * n + (m - (r + 1))) + a := by | |
| omega | |
| _ = (m - (r + 1)) + a * (n + 1) := by ring | |
| _ = (m - r - 1) + a * (n + 1) := by rw [hsubr] | |
| /-- | |
| 入力/前提: `0 < m`, `0 < a < m`, `b < m`, `m ≤ a*n+b`。 | |
| 主張: transformed 再帰側の直前商は `n - ((an+b)%m)/a` に等しい。 | |
| 内容: `floorProd_exponent_bridge` を transformed 側の分母 `a` に読み替えた形。 | |
| 証明: `d = ((m*c-b-1)/a)+1` を経由して `Nat.add_mul_div_right` で整理する。 | |
| 役割: transformed carry 補題で末尾ブロックの指数差を計算する。 | |
| -/ | |
| private lemma floorProd_transposed_prev_div_eq | |
| (n m a b : Nat) | |
| (hM : 0 < m) (_hA_lt : a < m) (hB_lt : b < m) (hA_pos : 0 < a) | |
| (hY : m ≤ a * n + b) : | |
| let c := (a * n + b) / m | |
| let k := ((a * n + b) % m) / a | |
| let b' := m - b - 1 + a | |
| (m * (c - 1) + b') / a = n - k := by | |
| 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 | |
| simpa only [c, y] using | |
| FloorProd.Internal.floorProd_div_pos_of_ge y m hM (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_lt 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_bounds : k * a ≤ r ∧ r ≤ k * a + a - 1 := by | |
| simpa only [k] using FloorProd.Internal.floorProd_div_bounds r a hA_pos | |
| rcases hk_bounds with ⟨hk_lo, hk_hi⟩ | |
| have hk_lt_n : k < n := | |
| FloorProd.Internal.floorProd_div_index_lt n a k r x hA_pos hx_pos hmc_sub hk_lo | |
| have hq : t / a = n - k - 1 := by | |
| simpa only [t] using | |
| FloorProd.Internal.floorProd_pred_div_eq n a k r x hA_pos hx_pos hmc_sub hk_lo hk_hi | |
| have hq' : (m * c - b - 1) / a = n - k - 1 := by | |
| simpa only using hq | |
| have hc_succ : (c - 1) + 1 = c := by | |
| simpa [Nat.succ_eq_add_one] using (Nat.succ_pred_eq_of_pos hc_pos) | |
| have hmul : m * (c - 1) + m = m * c := by | |
| calc | |
| m * (c - 1) + m = m * ((c - 1) + 1) := by rw [Nat.mul_add, Nat.mul_one] | |
| _ = m * c := by rw [hc_succ] | |
| have hnum : m * (c - 1) + (m - b - 1 + a) = (m * c - b - 1) + a := by | |
| have hb1_le_m : b + 1 ≤ m := Nat.succ_le_of_lt hB_lt | |
| have hsubm : m - b - 1 = m - (b + 1) := by omega | |
| calc | |
| m * (c - 1) + (m - b - 1 + a) | |
| = m * (c - 1) + (m - (b + 1)) + a := by | |
| rw [hsubm] | |
| ac_rfl | |
| _ = (m * (c - 1) + m - (b + 1)) + a := by | |
| rw [Nat.add_sub_assoc hb1_le_m] | |
| _ = (m * c - (b + 1)) + a := by rw [hmul] | |
| _ = (m * c - b - 1) + a := by | |
| omega | |
| calc | |
| (m * (c - 1) + (m - b - 1 + a)) / a = ((m * c - b - 1) + a) / a := by | |
| rw [hnum] | |
| _ = (m * c - b - 1) / a + 1 := by | |
| simpa [Nat.mul_comm] using (Nat.add_mul_div_right (m * c - b - 1) 1 hA_pos) | |
| _ = n - k := by | |
| rw [hq'] | |
| have hnk_pos : 0 < n - k := Nat.sub_pos_of_lt hk_lt_n | |
| calc | |
| (n - k - 1) + 1 = n - k := by | |
| simpa [Nat.succ_eq_add_one] using (Nat.succ_pred_eq_of_pos hnk_pos) | |
| /-- | |
| 入力/前提: `0 < m`, `0 < a < m`, `b < m`, `m ≤ a*n+b`。 | |
| 主張: transformed 再帰側の次商は `n + 1` に等しい。 | |
| 内容: `m*c + (m-b-1+a)` を `(m-r-1) + a*(n+1)` に分解して直接除算する。 | |
| 証明: 商余り分解と `m-r-1 < a` を用いる。 | |
| 役割: transformed carry 補題で末尾ステップの上段商を決める。 | |
| -/ | |
| private lemma floorProd_transposed_next_div_eq | |
| (n m a b : Nat) | |
| (hM : 0 < m) (_hA_lt : a < m) (hB_lt : b < m) (hA_pos : 0 < a) | |
| (hCarry : m ≤ (a * n + b) % m + a) : | |
| let c := (a * n + b) / m | |
| let b' := m - b - 1 + a | |
| (m * c + b') / a = n + 1 := by | |
| set y : Nat := a * n + b | |
| set c : Nat := y / m | |
| set r : Nat := y % m | |
| have hy : y = m * c + r := by | |
| calc | |
| y = y % m + m * (y / m) := by simpa using (Nat.mod_add_div y m).symm | |
| _ = m * c + r := by simp [c, r]; ac_rfl | |
| have hr_lt : r < m := by | |
| subst r | |
| exact Nat.mod_lt _ hM | |
| have hrest_lt : m - r - 1 < a := by | |
| simp [r] at hCarry | |
| omega | |
| have hnum : m * c + (m - b - 1 + a) = (m - r - 1) + a * (n + 1) := by | |
| have hy' : a * n + b = m * c + r := by simpa [y] using hy | |
| exact floorProd_transposed_next_num_eq n m a b c r hy' hB_lt hr_lt | |
| calc | |
| (m * c + (m - b - 1 + a)) / a = ((m - r - 1) + a * (n + 1)) / a := by | |
| rw [hnum] | |
| _ = (m - r - 1) / a + (n + 1) := by | |
| simpa [Nat.mul_comm] using (Nat.add_mul_div_right (m - r - 1) (n + 1) hA_pos) | |
| _ = n + 1 := by | |
| simp [Nat.div_eq_of_lt hrest_lt] | |
| /-- | |
| 入力/前提: `0 < m`, `0 < a < m`, `b < m`, `m ≤ a*n+b`。 | |
| 主張: 正規化済み `floorProdFormula` は tex の再帰式 | |
| `floor_prod(n,m,a,b;x,y) = floor_prod(c-1,a,m,m+a-b-1;y,x) * y * x^((an+b)%m/a)` | |
| を満たす。 | |
| 内容: 格子路の対角反転で `x,y` が交換され、末尾境界項として | |
| `y * x^⌊((an+b) % m)/a⌋` が現れる。 | |
| 役割: direct proof の再帰枝で必要な仕様側 recurrence を 1 本に隔離する。 | |
| -/ | |
| private lemma floorProdFormula_recurrence_normalized | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (x y : α) | |
| (hM : 0 < m) (hA_lt : a < m) (hB_lt : b < m) (hA_pos : 0 < a) | |
| (hY : m ≤ a * n + b) : | |
| FloorProd.Spec.floorProdFormula n m a b x y = | |
| FloorProd.Spec.floorProdFormula (((a * n + b) / m) - 1) a m (m - b - 1 + a) y x * | |
| y * x ^ (((a * n + b) % m) / a) := by | |
| induction n generalizing x y with | |
| | zero => | |
| omega | |
| | succ n ih => | |
| let c := (a * n + b) / m | |
| let r := (a * n + b) % m | |
| let k := r / a | |
| let b' := m - b - 1 + a | |
| by_cases hCarry : m ≤ r + a | |
| · have hqCarry : (a * (n + 1) + b) / m = c + 1 := by | |
| have hnum : a * (n + 1) + b = m * c + (r + a) := by | |
| calc | |
| a * (n + 1) + b = a * n + b + a := by ring | |
| _ = m * c + r + a := by | |
| rw [show a * n + b = m * c + r by | |
| simpa [c, r, Nat.add_comm] using (Nat.mod_add_div (a * n + b) m).symm] | |
| _ = m * c + (r + a) := by ac_rfl | |
| rw [hnum] | |
| apply (Nat.div_eq_iff hM).2 | |
| constructor | |
| · have hle := Nat.add_le_add_left hCarry (m * c) | |
| calc | |
| (c + 1) * m = m * c + m := by ring | |
| _ ≤ m * c + (r + a) := hle | |
| · have hsum_lt : r + a < m + m := Nat.add_lt_add (Nat.mod_lt _ hM) hA_lt | |
| have hle0 : r + a ≤ m + m - 1 := Nat.le_pred_of_lt hsum_lt | |
| have hle1 := Nat.add_le_add_left hle0 (m * c) | |
| calc | |
| m * c + (r + a) ≤ m * c + (m + m - 1) := hle1 | |
| _ = m * c + m + m - 1 := by omega | |
| _ = (c + 1) * m + m - 1 := by | |
| rw [Nat.add_mul, one_mul] | |
| ac_rfl | |
| by_cases hPrev : m ≤ a * n + b | |
| · have hIh := ih x y hPrev | |
| have hRecStep : | |
| FloorProd.Spec.floorProdFormula c a m b' y x = | |
| FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * (y * x ^ (k + 1)) := by | |
| have hc_pos : 0 < c := by | |
| simpa [c] using FloorProd.Internal.floorProd_div_pos_of_ge (a * n + b) m hM hPrev | |
| calc | |
| FloorProd.Spec.floorProdFormula c a m b' y x | |
| = FloorProd.Spec.floorProdFormula ((c - 1) + 1) a m b' y x := by | |
| have hc_succ : (c - 1) + 1 = c := by | |
| simpa [Nat.succ_eq_add_one] using (Nat.succ_pred_eq_of_pos hc_pos) | |
| rw [hc_succ] | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * | |
| (y * x ^ (((m * (c - 1 + 1) + b') / a) - ((m * (c - 1) + b') / a))) := by | |
| simpa using (FloorProd.Spec.floorProdFormula_succ (c - 1) a m b' y x) | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * | |
| (y * x ^ (((m * c + b') / a) - ((m * (c - 1) + b') / a))) := by | |
| rw [Nat.sub_add_cancel (Nat.succ_le_of_lt hc_pos)] | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * | |
| (y * x ^ (((m * c + b') / a) - (n - k))) := by | |
| have hprev : (m * (c - 1) + b') / a = n - k := by | |
| simpa [c, b', k] using | |
| floorProd_transposed_prev_div_eq n m a b hM hA_lt hB_lt hA_pos hPrev | |
| rw [hprev] | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * | |
| (y * x ^ ((n + 1) - (n - k))) := by | |
| have hnext : (m * c + b') / a = n + 1 := by | |
| simpa [c, b'] using | |
| floorProd_transposed_next_div_eq n m a b hM hA_lt hB_lt hA_pos hCarry | |
| rw [hnext] | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * (y * x ^ (k + 1)) := by | |
| have hbridge := | |
| FloorProd.Internal.floorProd_exponent_bridge n m a b hM hA_lt hB_lt hA_pos hPrev | |
| have hk_le_n : k ≤ n := by | |
| calc | |
| k = n - (((m * ((a * n + b) / m) - b - 1) / a) + 1) := by | |
| simpa [k] using hbridge.symm | |
| _ ≤ n := Nat.sub_le _ _ | |
| have hsub : (n + 1) - (n - k) = k + 1 := by | |
| have hEq : (n - k) + (k + 1) = n + 1 := by | |
| calc | |
| (n - k) + (k + 1) = ((n - k) + k) + 1 := by ac_rfl | |
| _ = n + 1 := by rw [Nat.sub_add_cancel hk_le_n] | |
| rw [← hEq, Nat.add_sub_cancel_left] | |
| rw [hsub] | |
| calc | |
| FloorProd.Spec.floorProdFormula (n + 1) m a b x y | |
| = FloorProd.Spec.floorProdFormula n m a b x y * (x * y) := by | |
| exact floorProdFormula_succ_of_carry n m a b x y hM hA_lt hCarry | |
| _ = (FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * y * x ^ k) * | |
| (x * y) := by | |
| rw [hIh] | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * | |
| (y * x ^ (k + 1)) * y := by | |
| simp [pow_succ, mul_assoc] | |
| _ = FloorProd.Spec.floorProdFormula c a m b' y x * y := by | |
| rw [hRecStep] | |
| _ = FloorProd.Spec.floorProdFormula (((a * (n + 1) + b) / m) - 1) a m b' y x * | |
| y * x ^ (((a * (n + 1) + b) % m) / a) := by | |
| have hkCurr0 : ((a * (n + 1) + b) % m) / a = 0 := by | |
| simpa using floorProd_step_mod_div_eq_zero_of_le n m a b hM hA_lt hCarry | |
| simp [b', c, hqCarry, hkCurr0] | |
| · have hPrevLt : a * n + b < m := Nat.lt_of_not_ge hPrev | |
| calc | |
| FloorProd.Spec.floorProdFormula (n + 1) m a b x y | |
| = FloorProd.Spec.floorProdFormula n m a b x y * (x * y) := by | |
| exact floorProdFormula_succ_of_carry n m a b x y hM hA_lt hCarry | |
| _ = x ^ n * (x * y) := by | |
| have hStopN : FloorProd.Spec.floorProdFormula n m a b x y = x ^ n := | |
| floorProdFormula_eq_pow_of_stop_normalized n m a b x y hM hA_lt hB_lt hPrevLt | |
| rw [hStopN] | |
| _ = x ^ (n + 1) * y := by | |
| rw [pow_succ]; simp [mul_assoc] | |
| _ = FloorProd.Spec.floorProdFormula 0 a m b' y x * y := by | |
| have hb'div : b' / a = n + 1 := by | |
| have hqPrev0 : (a * n + b) / m = 0 := Nat.div_eq_of_lt hPrevLt | |
| simpa [hqPrev0, mul_zero, zero_add] using | |
| floorProd_transposed_next_div_eq n m a b hM hA_lt hB_lt hA_pos hCarry | |
| simp [FloorProd.Spec.floorProdFormula, Nat.ne_of_gt hA_pos, hb'div] | |
| _ = FloorProd.Spec.floorProdFormula (((a * (n + 1) + b) / m) - 1) a m b' y x * | |
| y * x ^ (((a * (n + 1) + b) % m) / a) := by | |
| have hkCurr0 : ((a * (n + 1) + b) % m) / a = 0 := by | |
| simpa using floorProd_step_mod_div_eq_zero_of_le n m a b hM hA_lt hCarry | |
| have hqCurr1 : (a * (n + 1) + b) / m = 1 := by | |
| simpa using floorProd_step_div_eq_one_of_lt_of_le | |
| n m a b hM hA_lt hPrevLt hCarry | |
| simp [b', hqCurr1, hkCurr0] | |
| · have hNoCarry : r + a < m := by omega | |
| have hqNoCarry : (a * (n + 1) + b) / m = c := by | |
| simpa using floorProd_step_div_eq_of_lt n m a b hM hA_lt hNoCarry | |
| calc | |
| FloorProd.Spec.floorProdFormula (n + 1) m a b x y | |
| = FloorProd.Spec.floorProdFormula n m a b x y * x := by | |
| exact floorProdFormula_succ_of_no_carry n m a b x y hM hA_lt hNoCarry | |
| _ = (FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * y * x ^ k) * x := by | |
| have hPrev : m ≤ a * n + b := by | |
| have hCurrPos : 0 < (a * (n + 1) + b) / m := by | |
| exact FloorProd.Internal.floorProd_div_pos_of_ge (a * (n + 1) + b) m hM hY | |
| have hPrevPos : 0 < (a * n + b) / m := by | |
| have hcPos : 0 < c := by | |
| rw [← hqNoCarry] | |
| exact hCurrPos | |
| simpa [c] using hcPos | |
| exact Nat.le_of_not_lt (fun hlt => by | |
| have hq0 : (a * n + b) / m = 0 := Nat.div_eq_of_lt hlt | |
| exact (Nat.ne_of_gt hPrevPos) hq0) | |
| have hIh := ih x y hPrev | |
| rw [hIh] | |
| _ = FloorProd.Spec.floorProdFormula (c - 1) a m b' y x * y * x ^ (k + 1) := by | |
| simp [pow_succ, mul_assoc] | |
| _ = FloorProd.Spec.floorProdFormula (((a * (n + 1) + b) / m) - 1) a m b' y x * | |
| y * x ^ (((a * (n + 1) + b) % m) / a) := by | |
| have hkSucc : ((a * (n + 1) + b) % m) / a = k + 1 := by | |
| rw [floorProd_step_mod_eq_of_lt n m a b hM hNoCarry] | |
| simp [k, r] | |
| simpa [Nat.mul_comm] using | |
| (Nat.add_mul_div_right ((a * n + b) % m) 1 hA_pos) | |
| simp [b', c, hqNoCarry, hkSucc] | |
| end Internal | |
| /-- | |
| 入力/前提: `0 < st.m` と Euclid 側 fuel 十分性。 | |
| 主張: `floorProdLoop fuel st` は常に | |
| `st.pre * floorProdFormula st.n st.m st.a st.b st.x st.y * st.suf` | |
| に一致する。 | |
| 内容: 停止枝は閉形式補題、再帰枝は tex recurrence と tail の帰納法で処理する。 | |
| 証明: fuel に関する帰納法。 | |
| 役割: `floorProd_correct` を公開状態へ戻すための一般 loop invariant。 | |
| -/ | |
| lemma floorProdLoop_formula_invariant | |
| {α : Type _} [Monoid α] | |
| (fuel : Nat) (st : FloorProd.LoopState α) (hM : 0 < st.m) | |
| (hFuel : (Fuel.euclidN fuel st.a st.m).2 = 0) : | |
| Impl.floorProdLoop fuel st = | |
| st.pre * Spec.floorProdFormula st.n st.m st.a st.b st.x st.y * st.suf := by | |
| induction fuel generalizing st with | |
| | zero => | |
| exact False.elim <| | |
| (Nat.ne_of_gt hM) (by simpa only [Fuel.euclidN] using hFuel) | |
| | succ fuel ih => | |
| by_cases hc0 : ((st.a % st.m) * st.n + (st.b % st.m)) / st.m = 0 | |
| · let p := st.a / st.m | |
| let q := st.b / st.m | |
| let a' := st.a % st.m | |
| let b' := st.b % st.m | |
| let x' := st.x * st.y ^ p | |
| have ha'lt : a' < st.m := by | |
| simp only [a'] | |
| exact Nat.mod_lt _ hM | |
| have hb'lt : b' < st.m := by | |
| simp only [b'] | |
| exact Nat.mod_lt _ hM | |
| have hlt : a' * st.n + b' < st.m := by | |
| rcases (Nat.div_eq_zero_iff.mp hc0) with hm | hlt | |
| · exact False.elim ((Nat.ne_of_gt hM) hm) | |
| · simpa [a', b'] using hlt | |
| have hStop : | |
| FloorProd.Spec.floorProdFormula st.n st.m a' b' x' st.y = x' ^ st.n := by | |
| exact Internal.floorProdFormula_eq_pow_of_stop_normalized st.n st.m a' b' x' st.y | |
| hM ha'lt hb'lt hlt | |
| calc | |
| Impl.floorProdLoop (fuel + 1) st | |
| = (st.pre * st.y ^ (st.b / st.m)) * (st.x * st.y ^ (st.a / st.m)) ^ st.n * st.suf := | |
| FloorProd.Internal.floorProdLoop_stop_of_cprime_zero fuel st hc0 | |
| _ = st.pre * (st.y ^ q * (x' ^ st.n)) * st.suf := by | |
| simp [q, x', p, mul_assoc] | |
| _ = st.pre * FloorProd.Spec.floorProdFormula st.n st.m st.a st.b st.x st.y * st.suf := by | |
| rw [FloorProd.Spec.floorProdFormula_normalize st.n st.m st.a st.b st.x st.y hM, | |
| hStop] | |
| · 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 | |
| let d := ((st.m * c' - b' - 1) / a') + 1 | |
| let suf' := st.y * (x' ^ (st.n - d)) * st.suf | |
| let st' : FloorProd.LoopState α := | |
| { n := c' - 1 | |
| m := a' | |
| a := st.m | |
| b := st.m - b' - 1 + a' | |
| x := st.y | |
| y := x' | |
| pre := pre' | |
| suf := suf' } | |
| rcases FloorProd.Internal.floorProd_step_bounds_of_cprime_ne_zero st hM hc0 with | |
| ⟨ha_lt, hb_lt, ha_pos, hY⟩ | |
| rw [show Impl.floorProdLoop (fuel + 1) st = Impl.floorProdLoop fuel st' by | |
| simp [Impl.floorProdLoop, p, a', x', q, b', pre', c', d, suf', st', hc0]] | |
| rw [ih _ ha_pos (FloorProd.Internal.floorProd_fuel_tail fuel st.a st.m hM hFuel)] | |
| calc | |
| st'.pre * Spec.floorProdFormula st'.n st'.m st'.a st'.b st'.x st'.y * st'.suf | |
| = st.pre * | |
| (st.y ^ q * | |
| (Spec.floorProdFormula (c' - 1) a' st.m (st.m - b' - 1 + a') st.y x' * | |
| (st.y * x' ^ (st.n - d)))) * st.suf := by | |
| simp [st', pre', suf', mul_assoc] | |
| _ = st.pre * Spec.floorProdFormula st.n st.m st.a st.b st.x st.y * st.suf := by | |
| have ha'_lt : a' < st.m := by | |
| simpa [a'] using ha_lt | |
| have hb'_lt : b' < st.m := by | |
| simpa [b'] using hb_lt | |
| have ha'_pos : 0 < a' := by | |
| simpa [a'] using ha_pos | |
| have hY' : st.m ≤ a' * st.n + b' := by | |
| simpa [a', b'] using hY | |
| have hRecNorm : | |
| Spec.floorProdFormula st.n st.m a' b' x' st.y = | |
| Spec.floorProdFormula (c' - 1) a' st.m (st.m - b' - 1 + a') st.y x' * | |
| st.y * x' ^ (((a' * st.n + b') % st.m) / a') := by | |
| simpa [a', b', c', mul_assoc] using | |
| (Internal.floorProdFormula_recurrence_normalized st.n st.m a' b' x' st.y | |
| hM ha'_lt hb'_lt ha'_pos hY') | |
| have hExp : ((a' * st.n + b') % st.m) / a' = st.n - d := by | |
| symm | |
| simpa [a', b', c', d] using | |
| (FloorProd.Internal.floorProd_exponent_bridge st.n st.m a' b' | |
| hM ha'_lt hb'_lt ha'_pos hY') | |
| calc | |
| st.pre * | |
| (st.y ^ q * | |
| (Spec.floorProdFormula (c' - 1) a' st.m (st.m - b' - 1 + a') st.y x' * | |
| (st.y * x' ^ (st.n - d)))) * st.suf | |
| = st.pre * (st.y ^ q * Spec.floorProdFormula st.n st.m a' b' x' st.y) * | |
| st.suf := by | |
| rw [hRecNorm, hExp] | |
| simp [mul_assoc] | |
| _ = st.pre * Spec.floorProdFormula st.n st.m st.a st.b st.x st.y * st.suf := by | |
| rw [FloorProd.Spec.floorProdFormula_normalize | |
| st.n st.m st.a st.b st.x st.y hM] | |
| /-- | |
| 入力/前提: `m>0`。 | |
| 主張: 実装 `floorProd` は仕様 `floorProdFormula` と一致する。 | |
| 内容: 以後の公開側では、原義的な積仕様を正準仕様として採用する。 | |
| 役割: 公開側の中心正当化。 | |
| -/ | |
| theorem floorProd_correct | |
| {α : Type _} [Monoid α] | |
| (n m a b : Nat) (hM : 0 < m) (x y : α) : | |
| Impl.floorProd n m a b x y = Spec.floorProdFormula n m a b x y := by | |
| let st : FloorProd.LoopState α := | |
| { n := n, m := m, a := a, b := b, x := x, y := y, pre := 1, suf := 1 } | |
| simpa [Impl.floorProd, Impl.floorProdSt, st] using | |
| floorProdLoop_formula_invariant (Fuel.stepBoundOfM m) st hM | |
| (by simpa using Fuel.floorProdLoop_fuel_sufficient st) | |
| namespace Internal | |
| /-- | |
| 目的: Nat 添字版の目的関数を定義する。 | |
| 定義: `a*i + b*⌊(c*i+d)/m⌋`。 | |
| 入力/前提: `a b : Int`, `m c d i : Nat`。 | |
| 出力: 型 `Int` の値を返す。 | |
| 役割: floor_prod 側の `best/argmax` 正当性を記述する基底関数。 | |
| -/ | |
| private def phiNat (a b : Int) (m c d i : Nat) : Int := | |
| a * Int.ofNat i + b * Int.ofNat ((c * i + d) / m) | |
| /-- | |
| 目的: `floorProdSpec ... (mwfElemX a) (mwfElemY b)` が最大値と最小 argmax を返す述語を定義する。 | |
| 定義: `info? = some info` と、`phiNat` の上界・到達・最小性を束ねる。 | |
| 入力/前提: `n m c d : Nat`, `a b : Int`, `res : FloorProd.Internal.mwfElem`。 | |
| 出力: 型 `Prop` の値を返す。 | |
| 役割: 基底枝・帰納枝の floor_prod 正当性補題を統一した形で表す。 | |
| -/ | |
| private def IsArgmaxResult | |
| (n m c d : Nat) (a b : Int) (res : FloorProd.Internal.mwfElem) : Prop := | |
| ∃ info : FloorProd.Internal.BestInfo, | |
| res.info? = some info ∧ | |
| (∀ i, i < n → phiNat a b m c d i ≤ info.best) ∧ | |
| info.arg < n ∧ | |
| phiNat a b m c d info.arg = info.best ∧ | |
| (∀ i, i < n → phiNat a b m c d i = info.best → info.arg ≤ i) | |
| /-- | |
| 目的: `phiNat` 上で `info.best` が最大値として達成されるための基本条件を束ねる。 | |
| 定義: 上界・到達点・達成点の範囲条件をまとめる。 | |
| 役割: `mwf`/`mwfLr` 側への最大値復元補題の前提を短くする。 | |
| -/ | |
| private def PhiNatBestSpec | |
| (n m c d : Nat) (a b : Int) (info : FloorProd.Internal.BestInfo) : Prop := | |
| (∀ i, i < n → phiNat a b m c d i ≤ info.best) ∧ | |
| info.arg < n ∧ | |
| phiNat a b m c d info.arg = info.best | |
| /-- | |
| 目的: `phiNat` 上で `info` が最小 argmax である条件を束ねる。 | |
| 定義: `PhiNatBestSpec` に最小性条件を加えたもの。 | |
| 役割: 区間版 argmax 復元補題の前提を短くする。 | |
| -/ | |
| private def PhiNatArgmaxSpec | |
| (n m c d : Nat) (a b : Int) (info : FloorProd.Internal.BestInfo) : Prop := | |
| PhiNatBestSpec n m c d a b info ∧ | |
| (∀ i, i < n → phiNat a b m c d i = info.best → info.arg ≤ i) | |
| /-- | |
| 入力/前提: `n,m,c,d : Nat`。 | |
| 主張: `phiNat` の `n` から `n+1` への増分は、1 個の `X` と | |
| その直後に現れる `Y` 個数で表せる。 | |
| 内容: `q_n = floor((c*n+d)/m)`, `q_{n+1} = floor((c*(n+1)+d)/m)` とすると、 | |
| `phiNat(n+1) = phiNat(n) + a + b*(q_{n+1}-q_n)`。 | |
| 証明: 定義展開後、商の増分を `Nat.sub_add_cancel` で分解して整理する。 | |
| 役割: `R` を 1 つ増やしたときの floor_prod 側 1 ブロック追加と `phiNat` を対応させる。 | |
| -/ | |
| private lemma phiNat_succ_eq_add_step | |
| (n m c d : Nat) (a b : Int) : | |
| phiNat a b m c d (n + 1) = | |
| phiNat a b m c d n + | |
| (a + b * Int.ofNat (((c * (n + 1) + d) / m) - ((c * n + d) / m))) := by | |
| let q0 := (c * n + d) / m | |
| let q1 := (c * (n + 1) + d) / m | |
| have hq : q0 ≤ q1 := by | |
| exact Nat.div_le_div_right (Nat.add_le_add_right (Nat.mul_le_mul_left _ (Nat.le_succ _)) _) | |
| have hqsplitInt : (Int.ofNat q1 : Int) = Int.ofNat q0 + Int.ofNat (q1 - q0) := by | |
| simpa using | |
| (congrArg (fun t : Nat => (Int.ofNat t : Int)) (Nat.add_sub_of_le hq)).symm | |
| have hStep : | |
| a * Int.ofNat (n + 1) + b * Int.ofNat q1 = | |
| (a * Int.ofNat n + b * Int.ofNat q0) + (a + b * Int.ofNat (q1 - q0)) := by | |
| rw [hqsplitInt, show (Int.ofNat (n + 1) : Int) = Int.ofNat n + 1 by | |
| exact (Nat.cast_add n 1 : ((n + 1 : Nat) : Int) = _)] | |
| ring | |
| simpa [phiNat, q0, q1] using hStep | |
| /-- | |
| 入力/前提: 任意の `mwfElem` の右に 1 個の `X` ブロックを足す。 | |
| 主張: `info? = none` なら新しい prefix だけが候補になり、`info? = some info` なら | |
| 旧最大値と右端直前の累積和 `u.sum` の比較で `best/arg` が決まる。 | |
| 内容: 右端更新で増える新候補は最後の 1 ブロックを使う prefix しかない。 | |
| 証明: `u.info?` の場合分けと比較分岐をそのまま `mwfElemMul` から読む。 | |
| 役割: `floorProdSpec` の積仕様を `n ↦ n+1` の右端更新に読み替える基本式。 | |
| -/ | |
| private lemma mwfElem_mul_mwfElemX_right_cases | |
| (u : FloorProd.Internal.mwfElem) (step : Int) : | |
| FloorProd.Internal.mwfElemMul u (FloorProd.Internal.mwfElemX step) = | |
| match u.info? with | |
| | none => | |
| { sum := u.sum + step | |
| info? := some { best := u.sum, dx := 1, arg := 0 } } | |
| | some info => | |
| if info.best >= u.sum then | |
| { sum := u.sum + step | |
| info? := some { best := info.best, dx := info.dx + 1, arg := info.arg } } | |
| else | |
| { sum := u.sum + step | |
| info? := some { best := u.sum, dx := info.dx + 1, arg := info.dx } } := by | |
| rcases u with ⟨s, info⟩ | |
| cases info with | |
| | none => | |
| simp [FloorProd.Internal.mwfElemMul, FloorProd.Internal.mwfElemX] | |
| | some info => | |
| by_cases h : info.best >= s | |
| · simp [FloorProd.Internal.mwfElemMul, FloorProd.Internal.mwfElemX, h] | |
| · simp [FloorProd.Internal.mwfElemMul, FloorProd.Internal.mwfElemX, h] | |
| /-- | |
| 入力/前提: 任意の `mwfElem` の右に 1 個の `X` ブロックを足す。 | |
| 主張: `sum` 成分は常に `u.sum + step` に更新される。 | |
| 内容: `mwfElemX` は `best/arg` を持つが、`sum` 側には単に `step` を足すだけである。 | |
| 証明: `mwfElem_mul_mwfElemX_right_cases` の各枝を見れば `sum` は共通で同じ。 | |
| 役割: `floorProdFormula_mwfElem_sum_eq_phiNat` の帰納ステップを 1 行で済ませる。 | |
| -/ | |
| private lemma mwfElem_mul_mwfElemX_sum | |
| (u : FloorProd.Internal.mwfElem) (step : Int) : | |
| (FloorProd.Internal.mwfElemMul u (FloorProd.Internal.mwfElemX step)).sum = u.sum + step := by | |
| rcases u with ⟨s, info?⟩ | |
| cases info? with | |
| | none => | |
| simp [FloorProd.Internal.mwfElemMul, FloorProd.Internal.mwfElemX] | |
| | some info => | |
| simp [FloorProd.Internal.mwfElemMul, FloorProd.Internal.mwfElemX] | |
| split_ifs <;> rfl | |
| /-- | |
| 入力/前提: `res.info? = some info` の状態で右に 1 個の `X` ブロックを足し、 | |
| 結果が `some info'` を持つ。 | |
| 主張: 新しい `dx` は必ず `info.dx + 1` になる。 | |
| 内容: 右端に 1 ブロック追加すると、最良 prefix の長さは比較結果に関わらず 1 だけ伸びる。 | |
| 証明: `mwfElemMul` を展開し、2 分岐後の `info` を読む。 | |
| 役割: `floorProdFormula_mwfElem_isArgmaxResult` の succ 枝で `dx` 更新を 1 行化する。 | |
| -/ | |
| private lemma mwfElem_mul_mwfElemX_dx_of_info | |
| (res : FloorProd.Internal.mwfElem) (step : Int) | |
| (info info' : FloorProd.Internal.BestInfo) | |
| (hRes : res.info? = some info) | |
| (hMul : (res * FloorProd.Internal.mwfElemX step).info? = some info') : | |
| info'.dx = info.dx + 1 := by | |
| rcases res with ⟨s, info?⟩ | |
| cases info? with | |
| | none => | |
| cases hRes | |
| | some info0 => | |
| injection hRes with hInfoEq | |
| subst info0 | |
| have hMul' : | |
| (FloorProd.Internal.mwfElemMul { sum := s, info? := some info } | |
| (FloorProd.Internal.mwfElemX step)).info? = some info' := by | |
| simpa using hMul | |
| have hCases := congrArg FloorProd.Internal.mwfElem.info? | |
| (mwfElem_mul_mwfElemX_right_cases { sum := s, info? := some info } step) | |
| rw [hCases] at hMul' | |
| by_cases hCmp : info.best >= s | |
| · have hMul' : | |
| some { best := info.best, dx := info.dx + 1, arg := info.arg } = some info' := by | |
| simpa only [hCmp] using hMul' | |
| cases hMul' | |
| simp | |
| · have hMul' : | |
| some { best := s, dx := info.dx + 1, arg := info.dx } = some info' := by | |
| simpa only [hCmp] using hMul' | |
| cases hMul' | |
| simp | |
| /-- | |
| 入力/前提: `k : Nat`。 | |
| 主張: `mwfElemY b ^ k` は `sum = k*b`, `info? = none` に等しい。 | |
| 内容: `Y` は情報を持たないので、冪でも和だけが線形に伸びる。 | |
| 証明: `k` による帰納法と `mwfElemMul` の `none/none` 枝の展開で示す。 | |
| 役割: `q = 1` 基底枝で `floorProdSpec 0 ...` を `X` 冪へ簡約した後の整理に使う。 | |
| -/ | |
| private lemma mwfElemY_pow (b : Int) : | |
| ∀ k : Nat, (FloorProd.Internal.mwfElemY b) ^ k = | |
| { sum := Int.ofNat k * b, info? := none } | |
| | 0 => by | |
| have hOne : (1 : FloorProd.Internal.mwfElem) = { sum := 0, info? := none } := rfl | |
| simpa [Int.ofNat_eq_natCast] using hOne | |
| | k + 1 => by | |
| calc | |
| (FloorProd.Internal.mwfElemY b) ^ (k + 1) | |
| = (FloorProd.Internal.mwfElemY b) ^ k * FloorProd.Internal.mwfElemY b := by | |
| simp only [pow_succ] | |
| _ = ({ sum := Int.ofNat k * b, info? := none } : FloorProd.Internal.mwfElem) * | |
| FloorProd.Internal.mwfElemY b := by | |
| rw [mwfElemY_pow b k] | |
| _ = { sum := Int.ofNat k * b + b, info? := none } := by | |
| simpa [FloorProd.Internal.mwfElemY] using | |
| (FloorProd.Internal.MwfElemMul_none_none (Int.ofNat k * b) b) | |
| _ = { sum := Int.ofNat (k + 1) * b, info? := none } := by | |
| have hsum : Int.ofNat k * b + b = Int.ofNat (k + 1) * b := by | |
| calc | |
| Int.ofNat k * b + b = (Int.ofNat k + 1) * b := by ring | |
| _ = Int.ofNat (k + 1) * b := by | |
| simp only [Int.ofNat_eq_natCast, Nat.cast_add, Nat.cast_one] | |
| simp only [hsum] | |
| /-- | |
| 入力/前提: `res.info? = some info`。 | |
| 主張: `Y^q * res` は `best` を `q*b` だけ平行移動した `some info` を保つ。 | |
| 内容: 左側の `Y` 冪は `info` を持たないので、右側情報の位置は変わらない。 | |
| 証明: `mwfElemY_pow` で冪を閉形式化し、`mwfElemMul` の `none/some` 枝を展開する。 | |
| 役割: 正規化の前置因子 `Y^q` を argmax 証明へ戻すときに使う。 | |
| -/ | |
| private lemma mwfElemY_pow_mul_some | |
| (b s : Int) (q : Nat) (info : FloorProd.Internal.BestInfo) : | |
| (FloorProd.Internal.mwfElemY b) ^ q * | |
| { sum := s, info? := some info } = | |
| { sum := Int.ofNat q * b + s | |
| info? := some | |
| { best := Int.ofNat q * b + info.best | |
| dx := info.dx | |
| arg := info.arg } } := by | |
| rw [mwfElemY_pow] | |
| simpa [Int.ofNat_eq_natCast, Internal.MwfMkInfoFromScore, Internal.MwfShiftScore, | |
| Internal.MwfInfoScore, zero_add] using | |
| (FloorProd.Internal.MwfElemMul_none_some (Int.ofNat q * b) s info) | |
| /-- | |
| 入力/前提: 任意の指数 `k`。 | |
| 主張: `X a * Y^k` は 1 個の `X` 要素 `X (a + b*k)` に一致する。 | |
| 内容: 右側の `Y` 冪は `sum` だけを持つので、`X` の傾きに定数を加えるだけになる。 | |
| 証明: `mwfElemY_pow` で `Y` 冪を閉形式化し、`mwfElemMul` の `some/none` 枝を展開する。 | |
| 役割: `floorProdFormula_succ` の末尾ブロックを 1 個の `X` 更新へ落とす。 | |
| -/ | |
| private lemma mwfElemX_mul_mwfElemY_pow_eq_step | |
| (a b : Int) (k : Nat) : | |
| FloorProd.Internal.mwfElemX a * (FloorProd.Internal.mwfElemY b) ^ k = | |
| FloorProd.Internal.mwfElemX (a + b * Int.ofNat k) := by | |
| rw [mwfElemY_pow] | |
| simpa [FloorProd.Internal.mwfElemX, FloorProd.Internal.mwfElemY, mul_comm, | |
| mul_left_comm, mul_assoc] using | |
| (FloorProd.Internal.MwfElemMul_some_none a (Int.ofNat k * b) | |
| { best := 0, dx := 1, arg := 0 }) | |
| /-- | |
| 入力/前提: `0 < m`。 | |
| 主張: `floorProdFormula ... (X a) (Y b)` の `sum` 成分は `phiNat ... n` に一致する。 | |
| 内容: `floorProdFormula_succ` と `phiNat_succ_eq_add_step` は同じ右端 1 ステップ更新を表す。 | |
| 証明: `n` に関する帰納法で、末尾ブロックを `X` 1 個へまとめて比較する。 | |
| 役割: 右端更新で新候補値が `phiNat ... n` になることを保証する。 | |
| -/ | |
| private lemma floorProdFormula_mwfElem_sum_eq_phiNat | |
| (n m c d : Nat) (a b : Int) (hM : 0 < m) : | |
| (FloorProd.Spec.floorProdFormula n m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)).sum = | |
| phiNat a b m c d n := by | |
| induction n with | |
| | zero => | |
| simp [FloorProd.Spec.floorProdFormula, Nat.ne_of_gt hM, phiNat, mwfElemY_pow, mul_comm] | |
| | succ n ih => | |
| let delta : Nat := ((c * (n + 1) + d) / m) - ((c * n + d) / m) | |
| let step : Int := a + b * Int.ofNat delta | |
| calc | |
| (FloorProd.Spec.floorProdFormula (n + 1) m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)).sum | |
| = (FloorProd.Spec.floorProdFormula n m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b) * | |
| FloorProd.Internal.mwfElemX step).sum := by | |
| rw [FloorProd.Spec.floorProdFormula_succ n m c d, | |
| mwfElemX_mul_mwfElemY_pow_eq_step a b delta] | |
| _ = (FloorProd.Spec.floorProdFormula n m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)).sum + step := by | |
| exact mwfElem_mul_mwfElemX_sum | |
| (FloorProd.Spec.floorProdFormula n m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)) step | |
| _ = phiNat a b m c d n + step := by rw [ih] | |
| _ = phiNat a b m c d (n + 1) := by | |
| simpa [delta, step] using (phiNat_succ_eq_add_step n m c d a b).symm | |
| /-- | |
| 入力/前提: 長さ `n` の Nat 側問題で既存の最大値を保つ分岐に入る。 | |
| 主張: `best/arg` を保ったまま `dx` だけを 1 増やした結果は、長さ `n+1` でも正しい。 | |
| 内容: 新しい候補 `phiNat ... n` は旧最大値以下なので、最大値と最小 argmax は変化しない。 | |
| 証明: `mwfElem_mul_mwfElemX_right_cases` の `keep best` 枝を展開し、 | |
| `i < n+1` を `i < n` または `i = n` に分ける。 | |
| 役割: `isArgmaxResult_step` の既存最大値維持分岐を短く保つ。 | |
| -/ | |
| private lemma isArgmaxResult_step_keep_best | |
| (n m c d : Nat) (a b step s : Int) (info : FloorProd.Internal.BestInfo) | |
| (hUpper : ∀ i, i < n → phiNat a b m c d i ≤ info.best) | |
| (hArgLt : info.arg < n) | |
| (hHit : phiNat a b m c d info.arg = info.best) | |
| (hMin : ∀ i, i < n → phiNat a b m c d i = info.best → info.arg ≤ i) | |
| (hSum : s = phiNat a b m c d n) | |
| (hCmp : info.best >= s) : | |
| IsArgmaxResult (n + 1) m c d a b | |
| ({ sum := s, info? := some info } * FloorProd.Internal.mwfElemX step) := by | |
| refine ⟨{ best := info.best, dx := info.dx + 1, arg := info.arg }, ?_, ?_, ?_, ?_, ?_⟩ | |
| · simpa [hCmp] using congrArg FloorProd.Internal.mwfElem.info? | |
| (mwfElem_mul_mwfElemX_right_cases | |
| { sum := s, info? := some info } step) | |
| · intro i hi | |
| rcases Nat.lt_or_eq_of_le (Nat.le_of_lt_succ hi) with hin | rfl | |
| · exact hUpper i hin | |
| · simpa [hSum] using hCmp | |
| · exact Nat.lt_trans hArgLt (Nat.lt_succ_self n) | |
| · exact hHit | |
| · intro i hi hiEq | |
| rcases Nat.lt_or_eq_of_le (Nat.le_of_lt_succ hi) with hin | rfl | |
| · exact hMin i hin hiEq | |
| · exact Nat.le_of_lt hArgLt | |
| /-- | |
| 入力/前提: 長さ `n` の Nat 側問題で新しい末尾候補が旧最大値を真に上回る分岐に入る。 | |
| 主張: 新しい最大値は `phiNat ... n` で、その最小 argmax は `n` になる。 | |
| 内容: 旧区間の値はすべて旧最大値以下なので、新最大値より真に小さい。 | |
| 証明: `mwfElem_mul_mwfElemX_right_cases` の `take new suffix` 枝を展開し、 | |
| `i < n+1` を `i < n` または `i = n` に分ける。 | |
| 役割: `isArgmaxResult_step` の新最大値更新分岐を短く保つ。 | |
| -/ | |
| private lemma isArgmaxResult_step_take_new | |
| (n m c d : Nat) (a b step s : Int) (info : FloorProd.Internal.BestInfo) | |
| (hUpper : ∀ i, i < n → phiNat a b m c d i ≤ info.best) | |
| (hSum : s = phiNat a b m c d n) | |
| (hDxInfo : info.dx = n) | |
| (hCmp : ¬ info.best >= s) : | |
| IsArgmaxResult (n + 1) m c d a b | |
| ({ sum := s, info? := some info } * FloorProd.Internal.mwfElemX step) := by | |
| refine ⟨{ best := s, dx := info.dx + 1, arg := n }, ?_, ?_, ?_, ?_, ?_⟩ | |
| · simpa [hCmp, hDxInfo] using congrArg FloorProd.Internal.mwfElem.info? | |
| (mwfElem_mul_mwfElemX_right_cases | |
| { sum := s, info? := some info } step) | |
| · intro i hi | |
| rcases Nat.lt_or_eq_of_le (Nat.le_of_lt_succ hi) with hin | rfl | |
| · exact le_trans (hUpper i hin) (le_of_lt (lt_of_not_ge hCmp)) | |
| · simp [hSum] | |
| · exact Nat.lt_succ_self n | |
| · simp [hSum] | |
| · intro i hi hiEq | |
| rcases Nat.lt_or_eq_of_le (Nat.le_of_lt_succ hi) with hin | rfl | |
| · exact False.elim <| | |
| not_lt_of_ge (hUpper i hin) (by simpa [hiEq] using (lt_of_not_ge hCmp)) | |
| · exact le_rfl | |
| /-- | |
| 入力/前提: `res` が長さ `n` の Nat 側問題で最大値と最小 argmax を返し、 | |
| `res.sum = phiNat ... n` を満たす。 | |
| 主張: 右に `X step` を 1 個付けた結果は長さ `n+1` の問題で正しい。 | |
| 内容: 新しい候補は末尾 prefix `phiNat ... n` ただ 1 つであり、 | |
| 旧最大値との比較だけで `best/arg` が更新される。 | |
| 証明: `mwfElem_mul_mwfElemX_right_cases` の 2 分岐を、そのまま `phiNat` 側の | |
| 上界・到達・最小性へ移す。 | |
| 役割: `floorProdFormula_mwfElem_isArgmaxResult` の主帰納ステップ。 | |
| -/ | |
| private lemma isArgmaxResult_step | |
| (n m c d : Nat) (a b step : Int) (res : FloorProd.Internal.mwfElem) | |
| (hRes : IsArgmaxResult n m c d a b res) | |
| (hSum : res.sum = phiNat a b m c d n) | |
| (hDx : ∀ info, res.info? = some info → info.dx = n) : | |
| IsArgmaxResult (n + 1) m c d a b | |
| (res * FloorProd.Internal.mwfElemX step) := by | |
| rcases hRes with ⟨info, hInfo, hUpper, hArgLt, hHit, hMin⟩ | |
| rcases res with ⟨s, info?⟩ | |
| cases info? with | |
| | none => | |
| cases hInfo | |
| | some info0 => | |
| injection hInfo with hInfoEq | |
| subst info0 | |
| simp only at hSum | |
| by_cases hCmp : info.best >= s | |
| · exact isArgmaxResult_step_keep_best | |
| n m c d a b step s info hUpper hArgLt hHit hMin hSum hCmp | |
| · exact | |
| isArgmaxResult_step_take_new | |
| n m c d a b step s info hUpper hSum (hDx info rfl) hCmp | |
| /-- | |
| 入力/前提: `0 < m`。 | |
| 主張: 長さ 1 の `floorProdFormula ... (mwfElemX a) (mwfElemY b)` は、 | |
| `IsArgmaxResult` を満たし、さらに得られる `info.dx` は 1 である。 | |
| 内容: `Y^q * X step` の形へ落とすと、候補は添字 0 の 1 つだけになる。 | |
| 証明: `floorProdFormula_succ` を 1 回だけ展開し、`mwfElemY_pow_mul_some` で整理する。 | |
| 役割: `floorProdFormula_mwfElem_isArgmaxResult` の base 枝を 1 行化する。 | |
| -/ | |
| private lemma floorProdFormula_mwfElem_isArgmaxResult_one | |
| (m c d : Nat) (a b : Int) (hM : 0 < m) : | |
| IsArgmaxResult 1 m c d a b | |
| (FloorProd.Spec.floorProdFormula 1 m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)) ∧ | |
| (∀ info, | |
| (FloorProd.Spec.floorProdFormula 1 m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)).info? = some info → | |
| info.dx = 1) := by | |
| let q : Nat := d / m | |
| let delta : Nat := ((c * 1 + d) / m) - ((c * 0 + d) / m) | |
| let step : Int := a + b * Int.ofNat delta | |
| let info : FloorProd.Internal.BestInfo := | |
| { best := Int.ofNat q * b, dx := 1, arg := 0 } | |
| have hZero : | |
| FloorProd.Spec.floorProdFormula 0 m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b) = | |
| (FloorProd.Internal.mwfElemY b) ^ q := by | |
| simp [FloorProd.Spec.floorProdFormula, Nat.ne_of_gt hM, q] | |
| have hOne : | |
| FloorProd.Spec.floorProdFormula 1 m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b) = | |
| (FloorProd.Internal.mwfElemY b) ^ q * FloorProd.Internal.mwfElemX step := by | |
| rw [FloorProd.Spec.floorProdFormula_succ 0 m c d, hZero, | |
| mwfElemX_mul_mwfElemY_pow_eq_step a b delta] | |
| have hInfoEq : | |
| FloorProd.Spec.floorProdFormula 1 m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b) = | |
| { sum := Int.ofNat q * b + step, info? := some info } := by | |
| rw [hOne] | |
| simpa [q, step, info] using | |
| mwfElemY_pow_mul_some b step q { best := 0, dx := 1, arg := 0 } | |
| refine ⟨?_, ?_⟩ | |
| · refine ⟨info, ?_, ?_, ?_, ?_, ?_⟩ | |
| · simpa [info] using congrArg FloorProd.Internal.mwfElem.info? hInfoEq | |
| · intro i hi | |
| have hi0 : i = 0 := by omega | |
| subst hi0 | |
| simp [phiNat, q, info, mul_comm] | |
| · simp [info] | |
| · simp [phiNat, q, info, mul_comm] | |
| · intro i hi _ | |
| have hi0 : i = 0 := by omega | |
| subst hi0 | |
| simp [info] | |
| · intro info' hInfo' | |
| have hEq : info' = info := by | |
| apply Option.some.inj | |
| exact hInfo'.symm.trans | |
| (by simpa [info] using congrArg FloorProd.Internal.mwfElem.info? hInfoEq) | |
| subst hEq | |
| simp [info] | |
| /-- | |
| 入力/前提: `0<n`, `0<m`。 | |
| 主張: `floorProdFormula ... (mwfElemX a) (mwfElemY b)` は、`phiNat` の最大値と | |
| 最小 `argmax` を表す `IsArgmaxResult` を満たす。 | |
| 内容: Nat 添字側の主定理として、`info.best` が最大値、`info.arg` が最小 argmax | |
| であることを一括で述べる。 | |
| 役割: Step 3 の Nat 側正当化そのもの。 | |
| -/ | |
| private lemma floorProdFormula_mwfElem_isArgmaxResult | |
| (n m c d : Nat) (a b : Int) (hN : 0 < n) (hM : 0 < m) : | |
| IsArgmaxResult n m c d a b | |
| (FloorProd.Spec.floorProdFormula n m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)) := by | |
| obtain ⟨n, rfl⟩ := Nat.exists_eq_succ_of_ne_zero (Nat.ne_of_gt hN) | |
| have hMain : | |
| ∀ n, | |
| IsArgmaxResult (n + 1) m c d a b | |
| (FloorProd.Spec.floorProdFormula (n + 1) m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)) ∧ | |
| (∀ info, | |
| (FloorProd.Spec.floorProdFormula (n + 1) m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)).info? = some info → | |
| info.dx = n + 1) := by | |
| intro n | |
| induction n with | |
| | zero => | |
| exact floorProdFormula_mwfElem_isArgmaxResult_one m c d a b hM | |
| | succ n ih => | |
| rcases ih with ⟨ihArg, ihDx⟩ | |
| let prev := | |
| FloorProd.Spec.floorProdFormula (n + 1) m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b) | |
| let delta : Nat := ((c * ((n + 1) + 1) + d) / m) - ((c * (n + 1) + d) / m) | |
| let step : Int := a + b * Int.ofNat delta | |
| have hFormula : | |
| FloorProd.Spec.floorProdFormula ((n + 1) + 1) m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b) = | |
| prev * FloorProd.Internal.mwfElemX step := by | |
| rw [FloorProd.Spec.floorProdFormula_succ (n + 1) m c d, | |
| mwfElemX_mul_mwfElemY_pow_eq_step a b delta] | |
| refine ⟨?_, ?_⟩ | |
| · rw [hFormula] | |
| have hSum : prev.sum = phiNat a b m c d (n + 1) := by | |
| simpa [prev] using | |
| floorProdFormula_mwfElem_sum_eq_phiNat (n + 1) m c d a b hM | |
| exact isArgmaxResult_step (n + 1) m c d a b step prev | |
| ihArg hSum ihDx | |
| · intro info hInfo | |
| rcases ihArg with ⟨infoPrev, hInfoPrev, _hUpperPrev, _hArgLtPrev, _hHitPrev, _hMinPrev⟩ | |
| have hDxPrev : infoPrev.dx = n + 1 := ihDx infoPrev hInfoPrev | |
| have hStepDx : info.dx = infoPrev.dx + 1 := by | |
| apply mwfElem_mul_mwfElemX_dx_of_info prev step infoPrev info hInfoPrev | |
| simpa [hFormula] using hInfo | |
| simpa [hDxPrev] using hStepDx | |
| exact (hMain n).1 | |
| /-- | |
| 入力/前提: `0<n`, `0<m`。 | |
| 主張: `Impl.floorProd ... (mwfElemX a) (mwfElemY b)` 自体が | |
| `phiNat` の最大値と最小 argmax を返す `IsArgmaxResult` を満たす。 | |
| 内容: `floorProd_correct` で `Impl.floorProd` を仕様側 `floorProdFormula` に移し、 | |
| Nat 側主定理をそのまま適用する。 | |
| 役割: 区間版の `max/argmax` 証明で使う共通入口。 | |
| -/ | |
| private lemma floorProd_mwfElem_isArgmaxResult | |
| (n m c d : Nat) (a b : Int) (hN : 0 < n) (hM : 0 < m) : | |
| IsArgmaxResult n m c d a b | |
| (Impl.floorProd n m c d | |
| (FloorProd.Internal.mwfElemX a) (FloorProd.Internal.mwfElemY b)) := by | |
| simpa only [FloorProd.Correctness.floorProd_correct n m c d hM (FloorProd.Internal.mwfElemX a) | |
| (FloorProd.Internal.mwfElemY b)] using | |
| (floorProdFormula_mwfElem_isArgmaxResult n m c d a b hN hM : | |
| IsArgmaxResult n m c d a b | |
| (FloorProd.Spec.floorProdFormula n m c d (FloorProd.Internal.mwfElemX a) | |
| (FloorProd.Internal.mwfElemY b))) | |
| /-- | |
| 目的: 区間復元で使う平行移動・正規化後の補助量を束ねる。 | |
| フィールド: `qC,cI,qD,dI,aI,cst`。 | |
| 不変条件: 各フィールドは Step 4 の標準定義に従う。 | |
| 役割: 区間版 `mwfLr` / `argmax` 復元補題の setup 記述を短く保つ。 | |
| -/ | |
| private structure FloorProdTranslateData where | |
| qC : Int | |
| cI : Int | |
| qD : Int | |
| dI : Int | |
| aI : Int | |
| cst : Int | |
| /-- | |
| 入力/前提: 区間パラメータと `0<M`。 | |
| 主張: 区間復元で使う補助量 `qC,cI,qD,dI,aI,cst` をまとめて構成する。 | |
| 内容: `C,D` の正規化と `x = L + i` への平行移動に必要な定数を 1 つの値へ束ねる。 | |
| 役割: `phiNat` から `Spec.obj` / `mwfLr` へ戻す補題群の重複した setup を減らす。 | |
| -/ | |
| private def floorProdTranslateData | |
| (L M A B C D : Int) (hM : 0 < M) : FloorProdTranslateData := | |
| let qC := Spec.zfloorDiv C M hM | |
| let cI := Spec.zfloorMod C M hM | |
| let qD := Spec.zfloorDiv (C * L + D) M hM | |
| let dI := Spec.zfloorMod (C * L + D) M hM | |
| let aI := A + B * qC | |
| let cst := A * L + B * qD | |
| { qC, cI, qD, dI, aI, cst } | |
| /-- | |
| 入力/前提: `0<M`, `0≤c`, `0≤d` と Nat 添字 `i`。 | |
| 主張: 正規化済みの `Spec.obj a b c d M i` は `phiNat` に一致する。 | |
| 内容: `c,d,M` を Nat へ落としても床除算値が保たれることを使う。 | |
| 役割: 区間版証明で繰り返し現れる `Spec.obj` と `phiNat` の橋渡しを共通化する。 | |
| -/ | |
| private lemma obj_eq_phiNat_of_nonneg | |
| (a b c d M : Int) (i : Nat) | |
| (hM : 0 < M) (hc0 : 0 ≤ c) (hd0 : 0 ≤ d) : | |
| Spec.obj a b c d M (Int.ofNat i) hM = | |
| phiNat a b (Int.toNat M) (Int.toNat c) (Int.toNat d) i := by | |
| simp only [Spec.obj, Int.ofNat_eq_natCast, Spec.zfloorDiv, phiNat, Int.natCast_ediv, Nat.cast_add, | |
| Nat.cast_mul, Int.toNat_of_nonneg hc0, Int.toNat_of_nonneg hd0, | |
| Int.toNat_of_nonneg (le_of_lt hM)] | |
| /-- | |
| 入力/前提: `0<M` と Nat 添字 `i`。 | |
| 主張: 区間版目的関数 `Spec.obj` は、Step 4 の補助量 | |
| `qC,cI,qD,dI,aI,cst` を使って `cst + phiNat ... i` に分解できる。 | |
| 内容: `x = L + i` への平行移動後、` | |
| floor((C*(L+i)+D)/M) = qD + floor((cI*i+dI)/M)` を `obj` 展開へ代入する。 | |
| 役割: Step 4 の「Nat 側の argmax を区間 `[L,R)` へ戻す」橋渡し補題。 | |
| -/ | |
| private lemma phiNat_translate_to_obj | |
| (L M A B C D : Int) (hM : 0 < M) (i : Nat) : | |
| let qC := Spec.zfloorDiv C M hM | |
| let cI := Spec.zfloorMod C M hM | |
| let qD := Spec.zfloorDiv (C * L + D) M hM | |
| let dI := Spec.zfloorMod (C * L + D) M hM | |
| let aI := A + B * qC | |
| let cst := A * L + B * qD | |
| Spec.obj A B C D M (L + Int.ofNat i) hM = | |
| cst + phiNat aI B (Int.toNat M) (Int.toNat cI) (Int.toNat dI) i := by | |
| set qC : Int := Spec.zfloorDiv C M hM | |
| set cI : Int := Spec.zfloorMod C M hM | |
| set qD : Int := Spec.zfloorDiv (C * L + D) M hM | |
| set dI : Int := Spec.zfloorMod (C * L + D) M hM | |
| set aI : Int := A + B * qC | |
| set cst : Int := A * L + B * qD | |
| have hdI0 : 0 ≤ dI := by | |
| simpa only [dI, Spec.zfloorMod] using Int.emod_nonneg (C * L + D) (ne_of_gt hM) | |
| calc | |
| Spec.obj A B C D M (L + Int.ofNat i) hM | |
| = cst + Spec.obj A B C dI M (Int.ofNat i) hM := by | |
| simpa using | |
| Mwf.Correctness.Internal.obj_translate | |
| L M A B C D qD dI cst (Int.ofNat i) hM | |
| (by | |
| simpa only [qD, dI] using | |
| Mwf.Correctness.Internal.zfloorDiv_mod_decomp (C * L + D) M hM) | |
| rfl | |
| _ = cst + Spec.obj aI B cI dI M (Int.ofNat i) hM := by | |
| have hdIdiv0 : dI / M = 0 := | |
| Int.ediv_eq_zero_of_lt_abs hdI0 (by | |
| simpa only [dI, Spec.zfloorMod, abs_of_pos hM] using | |
| Int.emod_lt_of_pos (C * L + D) hM) | |
| have hdImod : dI % M = dI := by | |
| simpa [Spec.zfloorDiv, Spec.zfloorMod, hdIdiv0] using | |
| (Mwf.Correctness.Internal.zfloorDiv_mod_decomp dI M hM).symm | |
| simpa [aI, cI, qC, Spec.obj, Spec.zfloorDiv, Spec.zfloorMod, Impl.normS, | |
| Impl.normA, Impl.normC, Impl.normD, hdIdiv0, hdImod] using | |
| congrArg | |
| (fun z => cst + z) | |
| (Mwf.Internal.normalize_obj_eq A B C dI M 0 (Int.ofNat i) hM) | |
| _ = cst + phiNat aI B (Int.toNat M) (Int.toNat cI) (Int.toNat dI) i := by | |
| simpa using | |
| obj_eq_phiNat_of_nonneg aI B cI dI M i hM | |
| (by | |
| simpa only [cI, Spec.zfloorMod] using | |
| Int.emod_nonneg C (ne_of_gt hM)) | |
| hdI0 | |
| /-- | |
| 入力/前提: `L<R`, `0<M` と、Nat 側の `info` が最大値条件を満たすこと。 | |
| 主張: その `info.best` を区間版へ戻すと `mwfLr = cst + info.best` になる。 | |
| 内容: Nat 側 `phiNat` の上界・到達点を `Spec.obj` へ移し、 | |
| 平行移動された `mwfLr` の最大値と一致させる。 | |
| 役割: `max` 側と `argmax` 側の両方で使う区間復元の共通部。 | |
| -/ | |
| private lemma mwfLr_eq_cst_add_best_of_bounds | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) | |
| (info : FloorProd.Internal.BestInfo) : | |
| let nI := R - L | |
| let qC := Spec.zfloorDiv C M hM | |
| let cI := Spec.zfloorMod C M hM | |
| let qD := Spec.zfloorDiv (C * L + D) M hM | |
| let dI := Spec.zfloorMod (C * L + D) M hM | |
| let aI := A + B * qC | |
| let cst := A * L + B * qD | |
| PhiNatBestSpec (Int.toNat nI) (Int.toNat M) (Int.toNat cI) (Int.toNat dI) aI B info → | |
| mwfLr L R M A B C D hLR hM = cst + info.best := by | |
| simp only | |
| intro hSpec | |
| let T := floorProdTranslateData L M A B C D hM | |
| have hNI : 0 < R - L := by | |
| nlinarith [hLR] | |
| have hcI0 : 0 ≤ T.cI := by | |
| simpa only [T, floorProdTranslateData, FloorProdTranslateData.cI, Spec.zfloorMod] using | |
| Int.emod_nonneg C (ne_of_gt hM) | |
| have hdI0 : 0 ≤ T.dI := by | |
| simpa only [T, floorProdTranslateData, FloorProdTranslateData.dI, Spec.zfloorMod] using | |
| Int.emod_nonneg (C * L + D) (ne_of_gt hM) | |
| have hNormMwf : | |
| mwf (R - L) M A B C T.dI hNI hM = mwf (R - L) M T.aI B T.cI T.dI hNI hM := by | |
| have hdIdiv0 : T.dI / M = 0 := | |
| Int.ediv_eq_zero_of_lt_abs hdI0 (by | |
| simpa only [T, floorProdTranslateData, FloorProdTranslateData.dI, Spec.zfloorMod, | |
| abs_of_pos hM] using Int.emod_lt_of_pos (C * L + D) hM) | |
| have hdImod : T.dI % M = T.dI := by | |
| simpa [Spec.zfloorDiv, Spec.zfloorMod, hdIdiv0] using | |
| (Mwf.Correctness.Internal.zfloorDiv_mod_decomp T.dI M hM).symm | |
| calc | |
| mwf (R - L) M A B C T.dI hNI hM = | |
| B * (T.dI / M) + mwf (R - L) M T.aI B T.cI T.dI hNI hM := by | |
| simpa [T, floorProdTranslateData, hdImod, Impl.normS, Impl.normA, Impl.normC, | |
| Impl.normD] using | |
| Mwf.Internal.normalize_mwf_eq 0 (R - L) M A B C T.dI hNI hM | |
| _ = mwf (R - L) M T.aI B T.cI T.dI hNI hM := by simp [hdIdiv0] | |
| have hBestEqMwf : info.best = mwf (R - L) M T.aI B T.cI T.dI hNI hM := by | |
| rcases hSpec with ⟨hUpper, hArgLt, hHit⟩ | |
| have hObjEqPhi (i : Nat) : | |
| Spec.obj T.aI B T.cI T.dI M (Int.ofNat i) hM = | |
| phiNat T.aI B (Int.toNat M) (Int.toNat T.cI) (Int.toNat T.dI) i := by | |
| simpa using obj_eq_phiNat_of_nonneg T.aI B T.cI T.dI M i hM hcI0 hdI0 | |
| exact le_antisymm | |
| (((hObjEqPhi info.arg).trans hHit).symm ▸ | |
| Spec.obj_le_mwf (R - L) M T.aI B T.cI T.dI (Int.ofNat info.arg) hNI hM | |
| (by | |
| refine Finset.mem_Icc.mpr ⟨Int.natCast_nonneg info.arg, ?_⟩ | |
| have hArgLt' : Int.ofNat info.arg < R - L := by | |
| simpa only [Int.toNat_of_nonneg (le_of_lt hNI)] using Int.ofNat_lt.mpr hArgLt | |
| linarith)) | |
| (by | |
| rcases Mwf.Internal.exists_obj_eq_mwf (R - L) M T.aI B T.cI T.dI hNI hM with | |
| ⟨x, hxDom, hxEq⟩ | |
| have hx0 : 0 ≤ x := (Finset.mem_Icc.mp hxDom).1 | |
| have hxlt : x < R - L := by | |
| have hxle : x ≤ R - L - 1 := (Finset.mem_Icc.mp hxDom).2 | |
| linarith | |
| let j : Nat := Int.toNat x | |
| have hjlt : j < Int.toNat (R - L) := (Int.toNat_lt_toNat hNI).2 hxlt | |
| have hxj : Int.ofNat j = x := by | |
| simpa only [j] using Int.toNat_of_nonneg hx0 | |
| rw [← hxEq, ← hxj] | |
| calc | |
| Spec.obj T.aI B T.cI T.dI M (Int.ofNat j) hM | |
| = phiNat T.aI B (Int.toNat M) (Int.toNat T.cI) (Int.toNat T.dI) j := hObjEqPhi j | |
| _ ≤ info.best := hUpper j hjlt) | |
| rw [Mwf.Correctness.Internal.mwfLr_translate_eq_mwf | |
| L R (R - L) M A B C D T.qD T.dI T.cst hLR hNI hM rfl | |
| (by | |
| simpa [T, floorProdTranslateData] using | |
| Mwf.Correctness.Internal.zfloorDiv_mod_decomp (C * L + D) M hM) | |
| rfl, hNormMwf, ← hBestEqMwf] | |
| simp [T, floorProdTranslateData] | |
| /-- | |
| 入力/前提: `L<R`, `0<M` と、Nat 側の `info` が最大値条件と最小 argmax 条件を満たすこと。 | |
| 主張: その `info.arg` を区間版へ戻すと `mwfLrArgmax = L + info.arg` になる。 | |
| 内容: `phiNat_translate_to_obj` で達成点集合へ戻し、最小性も `L + i` へ移送する。 | |
| 役割: `floorProd_argmax_eq_mwfLrArgmax` の本体を共通化する。 | |
| -/ | |
| private lemma mwfLrArgmax_eq_translated_arg_of_bounds | |
| (L R M A B C D : Int) | |
| (hLR : L < R) (hM : 0 < M) | |
| (info : FloorProd.Internal.BestInfo) : | |
| let nI := R - L | |
| let qC := Spec.zfloorDiv C M hM | |
| let cI := Spec.zfloorMod C M hM | |
| let dI := Spec.zfloorMod (C * L + D) M hM | |
| let aI := A + B * qC | |
| PhiNatArgmaxSpec (Int.toNat nI) (Int.toNat M) (Int.toNat cI) (Int.toNat dI) aI B info → | |
| mwfLrArgmax L R M A B C D hLR hM = L + Int.ofNat info.arg := by | |
| simp only | |
| intro hSpec | |
| let T := floorProdTranslateData L M A B C D hM | |
| let s := mwfLrArgDom L R M A B C D hLR hM | |
| have hArgmin : | |
| L + Int.ofNat info.arg ∈ s ∧ | |
| ∀ x, x ∈ s → L + Int.ofNat info.arg ≤ x := by | |
| have hSpecT : | |
| PhiNatArgmaxSpec (Int.toNat (R - L)) (Int.toNat M) (Int.toNat T.cI) | |
| (Int.toNat T.dI) T.aI B info := by | |
| simpa [T, floorProdTranslateData, PhiNatArgmaxSpec, PhiNatBestSpec] using hSpec | |
| have hMaxEq : | |
| mwfLr L R M A B C D hLR hM = T.cst + info.best := by | |
| simpa [T, floorProdTranslateData] using | |
| mwfLr_eq_cst_add_best_of_bounds L R M A B C D hLR hM info | |
| (by simpa [T, floorProdTranslateData] using hSpecT.1) | |
| rcases hSpecT.1 with ⟨_, hArgLt, hHit⟩ | |
| refine ⟨?_, ?_⟩ | |
| · refine Finset.mem_filter.mpr ⟨?_, ?_⟩ | |
| · exact Finset.mem_Icc.mpr ⟨le_add_of_nonneg_right (Int.natCast_nonneg info.arg), by | |
| have : Int.ofNat info.arg < R - L := by | |
| simpa [T, floorProdTranslateData, | |
| Int.toNat_of_nonneg (sub_nonneg.mpr (le_of_lt hLR))] using | |
| Int.ofNat_lt.mpr hArgLt | |
| linarith⟩ | |
| · calc | |
| Spec.obj A B C D M (L + Int.ofNat info.arg) hM | |
| = T.cst + phiNat T.aI B (Int.toNat M) (Int.toNat T.cI) | |
| (Int.toNat T.dI) info.arg := by | |
| simpa [T, floorProdTranslateData] using | |
| phiNat_translate_to_obj L M A B C D hM info.arg | |
| _ = T.cst + info.best := by simpa [T] using congrArg (fun z => T.cst + z) hHit | |
| _ = mwfLr L R M A B C D hLR hM := by | |
| simpa [T, floorProdTranslateData] using hMaxEq.symm | |
| · intro x hx | |
| rcases Finset.mem_filter.mp hx with ⟨hxDom, hxEq⟩ | |
| rcases Mwf.Internal.exists_nat_offset_of_mem_domLr hLR hxDom with ⟨j, hjlt, rfl⟩ | |
| have hPhiEq : | |
| phiNat T.aI B (Int.toNat M) (Int.toNat T.cI) (Int.toNat T.dI) j = info.best := | |
| add_left_cancel <| calc | |
| T.cst + phiNat T.aI B (Int.toNat M) (Int.toNat T.cI) (Int.toNat T.dI) j | |
| = Spec.obj A B C D M (L + Int.ofNat j) hM := by | |
| simpa [T, floorProdTranslateData] using | |
| (phiNat_translate_to_obj L M A B C D hM j).symm | |
| _ = mwfLr L R M A B C D hLR hM := hxEq | |
| _ = T.cst + info.best := by | |
| simpa [T, floorProdTranslateData] using hMaxEq | |
| have hArgLe : info.arg ≤ j := hSpecT.2 j hjlt hPhiEq | |
| simpa only [add_comm] using add_le_add_left (Int.ofNat_le.mpr hArgLe) L | |
| unfold mwfLrArgmax | |
| simpa [s] using | |
| (le_antisymm (Finset.min'_le _ _ hArgmin.1) (hArgmin.2 _ (Finset.min'_mem _ _))) | |
| end Internal | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D`。 | |
| 主張: `max` と `argmax` の一致が示せれば、結果構造体も一致する。 | |
| 内容: 内部の同値定理の逆方向だけを公開する。 | |
| 証明: `Correctness.Internal` の同値定理へ成分等式の組を渡す。 | |
| 役割: `mwfLrWithArgmaxFloorProd` の正当化を組み立てる公開補題。 | |
| -/ | |
| theorem mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax | |
| (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 := by | |
| let nI := R - L | |
| let qC := Spec.zfloorDiv C M hM | |
| let cI := Spec.zfloorMod C M hM | |
| let qD := Spec.zfloorDiv (C * L + D) M hM | |
| let dI := Spec.zfloorMod (C * L + D) M hM | |
| let aI := A + B * qC | |
| let cst := A * L + B * qD | |
| let res : FloorProd.Internal.mwfElem := | |
| Impl.floorProd (Int.toNat nI) (Int.toNat M) (Int.toNat cI) (Int.toNat dI) | |
| (FloorProd.Internal.mwfElemX aI) (FloorProd.Internal.mwfElemY B) | |
| have hIsArgmax : | |
| Internal.IsArgmaxResult | |
| (Int.toNat nI) (Int.toNat M) (Int.toNat cI) (Int.toNat dI) aI B res := by | |
| have hNnat : 0 < Int.toNat (R - L) := | |
| Mwf.Fuel.Internal.int_toNat_pos_of_pos (by nlinarith [hLR]) | |
| have hMnat : 0 < Int.toNat M := | |
| Mwf.Fuel.Internal.int_toNat_pos_of_pos hM | |
| simpa [nI, qC, cI, qD, dI, aI, cst, res] using | |
| (Internal.floorProd_mwfElem_isArgmaxResult | |
| (Int.toNat (R - L)) (Int.toNat M) | |
| (Int.toNat (Spec.zfloorMod C M hM)) | |
| (Int.toNat (Spec.zfloorMod (C * L + D) M hM)) | |
| (A + B * Spec.zfloorDiv C M hM) B hNnat hMnat) | |
| obtain ⟨info, hResInfo, hArgmaxSpec⟩ : | |
| ∃ info : FloorProd.Internal.BestInfo, | |
| res.info? = some info ∧ | |
| Internal.PhiNatArgmaxSpec | |
| (Int.toNat nI) (Int.toNat M) (Int.toNat cI) (Int.toNat dI) aI B info := by | |
| simpa [Internal.IsArgmaxResult, Internal.PhiNatArgmaxSpec, | |
| Internal.PhiNatBestSpec, and_assoc] using hIsArgmax | |
| have hResInfo' : | |
| (Impl.floorProd (Int.toNat (R - L)) (Int.toNat M) (Int.toNat (C % M)) | |
| (Int.toNat ((C * L + D) % M)) | |
| (FloorProd.Internal.mwfElemX (A + B * (C / M))) | |
| (FloorProd.Internal.mwfElemY B)).info? = some info := by | |
| simpa [nI, qC, cI, qD, dI, aI, cst, res, Spec.zfloorDiv, Spec.zfloorMod] using hResInfo | |
| have hMaxEq : | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLr L R M A B C D hLR hM := by | |
| calc | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = cst + info.best := by | |
| simp [mwfLrFloorProd, mwfLrWithArgmaxFloorProd, cst, qD, hResInfo'] | |
| _ = mwfLr L R M A B C D hLR hM := by | |
| simpa [nI, qC, cI, qD, dI, aI, cst, res] using | |
| (Internal.mwfLr_eq_cst_add_best_of_bounds | |
| L R M A B C D hLR hM info hArgmaxSpec.1).symm | |
| have hArgEq : | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrArgmax L R M A B C D hLR hM := by | |
| calc | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = L + Int.ofNat info.arg := by | |
| simp [mwfLrArgmaxFloorProd, mwfLrWithArgmaxFloorProd, hResInfo'] | |
| _ = mwfLrArgmax L R M A B C D hLR hM := by | |
| simpa [nI, qC, cI, qD, dI, aI, cst, res] using | |
| (Internal.mwfLrArgmax_eq_translated_arg_of_bounds | |
| L R M A B C D hLR hM info hArgmaxSpec).symm | |
| ext | |
| · simpa [mwfLrFloorProd, mwfLrWithArgmax] using hMaxEq | |
| · simpa [mwfLrArgmaxFloorProd, mwfLrWithArgmax] using hArgEq | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D` と構造体レベルの一致。 | |
| 主張: そのとき `max` 成分も一致する。 | |
| 内容: `mwfLrWithArgmaxFloorProd = mwfLrWithArgmax` から第1成分を射影する。 | |
| 証明: 内部の同値定理の順方向から第1成分を取り出す。 | |
| 役割: `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) : | |
| mwfLrFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLr L R M A B C D hLR hM := by | |
| simpa only [mwfLrFloorProd, mwfLrWithArgmax] using | |
| congrArg mwfWithArgResult.max | |
| (mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax | |
| L R M A B C D hLR hM hC0 hD0) | |
| /-- | |
| 入力/前提: `L<R`, `0<M`, `0≤C`, `0≤D` と構造体レベルの一致。 | |
| 主張: そのとき `argmax` 成分も一致する。 | |
| 内容: `mwfLrWithArgmaxFloorProd = mwfLrWithArgmax` から第2成分を射影する。 | |
| 証明: 内部の同値定理の順方向から第2成分を取り出す。 | |
| 役割: `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) : | |
| mwfLrArgmaxFloorProd L R M A B C D hLR hM hC0 hD0 = | |
| mwfLrArgmax L R M A B C D hLR hM := by | |
| simpa only [mwfLrArgmaxFloorProd, mwfLrWithArgmax] using | |
| congrArg mwfWithArgResult.argmax | |
| (mwfLrWithArgmaxFloorProd_eq_mwfLrWithArgmax | |
| L R M A B C D hLR hM hC0 hD0) | |
| end Correctness | |
| end FloorProd | |
| end Mwf |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment