Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「証明はAC」で済ませない 〜Leanで競技プログラミング〜

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for KowerKoint KowerKoint
June 13, 2026
170

「証明はAC」で済ませない 〜Leanで競技プログラミング〜

λ Kansai in Summer 2026の発表内容

Avatar for KowerKoint

KowerKoint

June 13, 2026

Transcript

  1. 自己紹介 • 名前: KowerKoint • X: @KowerKoint2010 • 所属など: ‣

    大阪大学 修士 2 年 (来年は就職予定) ‣ アルゴリズム/理論計算機科学系の研究をボチボチ • 競プロ: AtCoder 黄、ICPC World Finals 進出予定(?) • 関数型: ‣『すごい Haskell たのしく学ぼう! 』を読んで感銘を受けた ‣ 純粋な数学への興味もあり、圏論を少し勉強中 ‣ Lean は興味はあったがほぼこの発表のために勉強 λ Kansai in Summer 2026 3
  2. エスパーで終わらせたくなる問題の例 問題設定 • 2𝑁 人の人がいる。人 𝑖 の身長は 𝐴𝑖 である。 •

    これらの人を 𝑁 組のペアに分ける • ペア (𝑖, 𝑗) のスコアを |𝐴𝑖 − 𝐴𝑗 | とするとき、 𝑁 個のペアのスコアの最小値を最大化せよ。 ‣ つまり、全ペアが 𝑥 以上の身長差を持てるような 𝑥 の最大値を求めよ • 1 ≤ 𝑁 ≤ 2 × 105, 1 ≤ 𝐴𝑖 ≤ 109 λ Kansai in Summer 2026 7
  3. エスパーで終わらせたくなる問題の例 問題設定 ペア (𝑖, 𝑗) のスコアを |𝐴𝑖 − 𝐴𝑗 |

    とするとき、𝑁 個のペアのスコアの 最小値を最大化せよ。 •「それっぽい」解法 ‣ 𝐴1 ≤ 𝐴2 ≤ … ≤ 𝐴2𝑁 となるようにソートしておく ‣ (1, 𝑁 + 1), (2, 𝑁 + 2), …, (𝑁, 2𝑁) のように分けるのが最適 • あってそう。でも証明はめんどくさいから一旦提出するか!→AC • これがエスパー (本当の証明は読者への宿題) λ Kansai in Summer 2026 8
  4. Lean 4 の概要 • 純粋関数型プログラミング言語かつ定理証明支援系 • 型の宇宙階層を扱える ‣ Nat Int

    List Nat … 等の一般的な「型」は 1 階の型 ‣ 命題 ∀ a b : Nat, a + b = b + a の型は Prop 型 (これも 1 階) ‣ ∀ a b : Nat, a + b = b + a を 0 階の型として扱うと、その値は この命題の証明 • 依存型も扱える ‣ 𝑛 未満の自然数の型、長さ 𝑛 のリストの型などを扱える • 伝わらないと思うが、相当美しくて興奮すべきことを言ってる ‣ 興味が出た方は一緒に Lean に入門しましょう! λ Kansai in Summer 2026 10
  5. Lean 4 でのプログラム記述と証明記述の例 • 通常の関数と定理が同様に定義できていることがわかる def sum : List Nat

    → Nat | [] => 0 | x :: xs => x + sum xs theorem replicate_sum : ∀ n x, sum (List.replicate n x) = n * x := by intro n x induction n with | zero => simp [List.replicate, sum] | succ n ih => simp [List.replicate, sum, ih] rw [Nat.add_mul, Nat.one_mul, Nat.add_comm] λ Kansai in Summer 2026 11
  6. Lean で競プロの実装をするのは難しい? • ランダムアクセス可能な配列もあるし for 文も使える def knapsack (wvs :

    List (Nat × Nat)) (W : Nat) : Nat := Id.run do let mut dp := Array.replicate (W + 1) 0 for (w, v) in wvs do let mut ndp := dp for i in [0:W+1] do let nw := i + w let nv := dp[i]! + v if nw <= W && ndp[nw]! < nv then ndp := ndp.set! nw nv dp := ndp dp.toList.max?.getD 0 λ Kansai in Summer 2026 12
  7. Lean で競プロの実装をするのは難しい? • ABC の過去問などを色々解いてみた • ランダムアクセス可能な配列もあるし for 文も使える ‣

    しかもこれで美しい型システムを乱してないんです! • 標準ライブラリのデータ構造が手薄 ‣ これを再実装する運命にあるのは C 言語プレイヤーと同じ • 入出力は一癖あるが、それほどやばくもない ‣ マクロも作れるし、えびさんがやってる • 集合知は全然得られない (が、LLM が何でも教えてくれる) • コンパイル言語だし実行速度は絶望的ではない (次スライド) • 結論: 意外と絶望的ではなく、信念があれば戦えそう! λ Kansai in Summer 2026 13
  8. Lean の実行速度 • AtCoder の EDPC-D (ナップサック問題) の標準的な実装で検証 言語 実行時間

    C++23 (GCC 15.2.0) 13ms Python (CPython 3.13.7) 707ms Python (PyPy 3.11-v7.3.20) 136ms Lean (lean v4.22.0) 62ms • 上級者も多い PyPy と張り合える性能なので、ほとんど不便ない • 末尾再帰なども最適化されるので結構戦えている λ Kansai in Summer 2026 14
  9. Yokan Party の証明 (今回の検証で一番しんどかった部分ですが、内容もハードなので時間 があれば記事にまとめたりします) • 現代競プロで最も有名と思われる問題、Yokan Party を実装して、 さらにそれで最適な解が出ることを証明してみた(実際のコード)

    • 実装は 50 行以下だが、証明まで含めると 400 行以上 • AI の支援を受けながらもできる限り自力で書いた • メインの二分探索の正当性だけでなくて判定部分に使っている 貪欲アルゴリズムも、完全証明を書いてみるとなかなか大変だっ た λ Kansai in Summer 2026 16
  10. 計算量も保証できる? • みんな大好き、モナドを定義していきます instance : Functor Costed where map f

    x := ⟨f x.value, x.cost⟩ instance : Applicative Costed where pure x := ⟨x, 0⟩ seq f x := let x' := x () ⟨f.value x'.value, f.cost + x'.cost⟩ instance : Monad Costed where bind x f := let y := f x.value ⟨y.value, x.cost + y.cost⟩ λ Kansai in Summer 2026 18
  11. 計算量も保証できる? • Costed.step を適用した関数の回数を数え上げられる • ↓は、二分探索で評価関数を適用 (p mid) した回数 def

    upper_bound_by (p : Nat → Bool) (ok ng : Nat) : Costed Nat := if h : ng - ok <= 1 then pure ok else let mid := (ok + ng) / 2 do let b ← Costed.step (p mid) if b then upper_bound_by p mid ng else upper_bound_by p ok mid λ Kansai in Summer 2026 20
  12. 計算量も保証できる? • Costed を使って計算ステップ数を保持しながら計算できる • そのコストを不等式証明することは原理上は可能 • どこを step (ボトルネックと見て加算)

    とするかは人間に 委ねられるため、完全証明とは言い難い • 関数適用のたびに自動でコストを加算できないかも考えたが、 モナド則を守りながらそれを実現するのは困難 • 実用的な Lean での計算量の証明は未実践だが、現実的には 実実行時間の計測や自然言語での証明のほうが便利と思われる λ Kansai in Summer 2026 21
  13. 貢献 1: 作問のミスを防げる • 作問では、想定解を自分で用意してテストケースを作る • これが間違っていたら問題として破綻!絶対に避けたい • 通常複数人で確認するし、生成 AI

    も使えるが、それでも 100% 合っているわけではない • Lean で想定解を作って証明もすればかなり確実性が上がる! ‣ もちろん生成 AI に任せれば良い • 自作の難問 (Game on “L”s)の解法証明を Codex に書かせた ‣ かなり複雑な場合分けを要する問題で、本番の正解者も 0 人 ‣ 人間向けに雑な感じで書いた解説を渡した ‣ 数時間かけて 1898 行の証明を無事完遂してくれた λ Kansai in Summer 2026 23
  14. 貢献 2: 新しいタイプのコンテスト • 以下のような問題は、従来の採点形式では採点が困難 ‣ 操作ごとに 𝑁! 要素の確率分布をシミュレーションする必要が あり、計算量が爆発

    問題設定 𝑁(1 ≤ 𝑁 ≤ 105) 枚のカードからなる山札がある。以下の操作を 𝑁 回以下の回数繰り返すことで、𝑁! 通りのカードの並び替え すべてが等確率で得られるようにできるか。できるなら操作列を 1 つ出力せよ。 • 操作: 連続する何枚かのカードを選んでランダムに巡回シフト λ Kansai in Summer 2026 24
  15. 貢献 2: 新しいタイプのコンテスト • このような問題も、参加者に出力の正当性証明まで Lean で 示させることで採点できるようになる • Lean

    での定理証明をオンラインジャッジ形式で出題している 既存のサイトとして Lean Online Judge や Lean4OJ があるが、 アルゴリズム (離散数学) にフォーカスしたものはなく、 まだまだ未開の領域がたくさんある λ Kansai in Summer 2026 25
  16. まとめ • Lean で競プロは意外とできる • 解けるだけでなくて、実装の証明までできる ‣ 証明はかなり骨の折れる作業だが、生成 AI なら結構できる

    • 問題を解くだけでなく、作問にも使えるし、新たな コンテストスタイルまで開拓できそう • 個人的な感想 ‣ Lean という言語が大好きな言語になった ‣ Lean でできることをもっと開拓していきたい λ Kansai in Summer 2026 26