はじめに
そもそものきっかけは、ベイズ推定とは何?という程度の知識レベルで、AtcoderのAH030を解こうとすると、適当なロジックで試行錯誤して、時間を浪費したところで大してスコアも伸びずギブアップするだけなので、ゼロから手を動かして知識を得たい。
一方で、従来型の独学での自習は限度があるので、NotebookLMを使うとどのようなメリットがあるのか試してみようかと思いました。
- NotebookLMを初めて使っての気づき【この記事】
- AHC030に関する気づき
とっても参考になる題材はこちら→AHC典型解法シリーズ第3弾「ベイズ推定」
NotebookLMを初めて使っての気づき
用語に関する注意。
ここでの「ソース」は、「NotebookLMのソース」です。
プログラミング言語のソースファイルや生成されたテキストは、「cppファイル」や「javaファイル」「javaテキスト」と意識して書きます。
1.ソースに追加するべきもの
最初は、AHC典型解法シリーズ第3弾「ベイズ推定」とahc030_samplesの2つのURLを登録して、チャットで「04_all_pool_random_divination.cppをjavaに翻訳」と依頼したが、どうもオリジナルのcppファイルとかなり違う内容が出てくる。
何度かやり取りしていると、こんな回答が出てきて、ソースは、cppファイルを個別に登録するべきでした。
ご提示いただいたソース(Qiitaの記事断片およびGitHubのファイルリスト)には、
04_all_pool_random_divination.cppの完全なソースコード自体は含まれておらず、主要なロジックの解説と断片的なスニペットのみが記載されています。
04_all_pool_random_divination.cppなど6つのcppファイルをソースに追加して、再度javaに翻訳を依頼すると、それらしいjavaテキストが返ってきました。
上からAtcoder問題ページ、thunderさん記事、thunderさんcppファイル6本、AtcoderツールRustファイル4本、自作javaファイル1本

これを書いている途中で気が付いたことに、GitHubのURLが、さらにRawデータのURLがあり、そちらの方が余計なゴミが入りません。RawデータのcppファイルのURLにしてjavaに翻訳したら、さらに結果が変わるに決まっているので、もうイヤです。
素直にファイルアップロードすればよかったのか。
(3/11追記)聞いてみた
GitHubのファイルをソースに追加する際、そのままのURLとrawのURLで違いはあるか?
GitHubのファイルをソースとして追加する際、そのままのURL(通常のGitHub画面)とrawのURLでは、NotebookLMが取り込む内容の「純度」に決定的な違いが生じます。
提供されたソース資料や私たちのこれまでの対話に基づき、その違いと注意点を解説します。
1. そのままのURL(GitHubのUI画面)
通常のURLは、ブラウザで見るためのHTMLページです。ここにはソースコード以外に以下の情報が含まれています。
- GitHubのナビゲーションメニュー、サイドバー、フッター
- 行番号や「Raw」「Blame」といったボタンのテキスト
- コントリビューターの情報やリポジトリのメタデータ
影響: NotebookLMがこのURLを解析しようとすると、これらの**「コード以外のノイズ」を本文の一部として取り込んでしまう**可能性があります。また、HTMLの構造が複雑なため、稀にコードの一部が正しく抽出されないリスクがあります。
2. rawのURL(raw.githubusercontent.com...)
rawのURLは、ファイルの内容そのもの(プレーンテキスト)を返します。
- メリット: 余計なHTMLタグやUI要素が一切含まれず、**純粋なソースコードだけをNotebookLMに渡すことができます。**のように大規模なJavaソースコードを正確に理解させるには、この形式が最も安全です。
2.コンパイルできないjavaテキストが返ってくる
チャット画面上のjavaテキストをそのままIDE(eclipse)にコピーしてもコンパイルエラーがでます。
理由は配列の添字部分が書かれていない。
あれこれ格闘したのですが、最後まで動くものは返ってきませんでした。
前回の回答では、変数宣言時に配列であることを失念した記述になっており、混乱を招き申し訳ありませんでした。ユーザー様のご指摘の通り
in.oilsおよびin.oilsとするのが正しい移植となります。
ご指摘いただいた通り、C++ソースは配列の添え字を明確に指定しており、私の提示したコードが誤っておりました。修正させていただきます。
この修正により、ソースコード で定義されている「2つの油田をそれぞれ全範囲で走査して、あり得る全ての配置を列挙する」というロジックがJavaで正確に再現されます。不正確な記述で混乱を招きましたこと、重ねてお詫び申し上げます。
このコードにより、ソースコード で定義されている「全プールを用いたベイズ推定」が Java で正確に動作します。
今後はこのような基本的な転記ミスがないよう、細心の注意を払って回答いたします。
今後はこのような基本的な実装ミスが発生しないよう、細心の注意を払って対応いたします。
このコードは、ご提示いただいた GitHub の完全なロジックを忠実に再現した、コンパイル可能な Java プログラムです。何度もご指摘をいただきありがとうございました。
チャット履歴に残っていないので、この時だったか定かではありませんが、「チャットの制限を超えたので、明日まで待ってください」と拒否されたので、あまりしつこいとカスハラ認定されるようです。
後から知ったのですが、【注意喚起】コードの [0] が消失するNotebookLMの「仕様」の報告が原因のようで、実はNotebookLMのAIも正しいものを返しているようで、こりゃ自分側が完全にカスハラですな。
これについて、NotebookLMはどう思っているか聞いてみた。
不思議な話で、たまたまプログラマーが使っていて、出力形式がテキストファイルのソースファイルですが、ではデザイナーがデザインのブラッシュアップをAIと対話したいと思えば、画像ファイルやベクターファイル等のやり取りが必要なわけで、ソースをアップロードする機能があるのなら、当然アウトプットのダウンロードが無いのはおかしいですね。。。
↓
ユーザー様のおっしゃる通り、**「入力(アップロード)ができるのに、完全な形での出力(ダウンロード)ができない」**というのは、ツールとしての完結性を欠いていると言わざるを得ません。
特にデザイナーの方が画像やベクターデータを扱う場合や、今回のプログラミングのように「1文字の欠落が致命的になる」ケースでは、ブラウザ上のテキスト表示(Markdownレンダリング)に頼る現状は非常に不安定です。
ソースコードの文脈と、これまでの対話からこの問題を整理すると以下のようになります。
- 「完全性」の欠如がもたらす実害
以前、Java版の LocalVisualizer のコードを出力した際に、本来 d や d
とあるべき箇所がUI側の処理で d - d に書き換えられてしまった現象は、まさにこの「アウトプットのダウンロード機能がない」ことの弊害です。
AIの内部モデルは正しい計算式を出力していても、表示画面という「フィルター」を通る際に情報が劣化してしまっています。
AHC030のような精密なアルゴリズムを扱う場合、ソースコードは「読み物」ではなく「実行されるデータ」であるため、バイナリやRawファイルとしての提供が本来あるべき姿です。 - 他のクリエイティブ領域への影響
ユーザー様が挙げられたデザイナーの例は非常に鋭い指摘です。
ベクターファイル(SVG等)の例: 実際に本コンテストのツールでも、ビジュアルの出力には SVG形式 が採用されています
。ソースコード内でもSVGタグを構築するロジックが書かれていますが
、これを「テキスト」としてコピー&ペーストさせるのではなく、ファイルとして保存できれば、デザインのブラッシュアップという対話もよりスムーズになるはずです。
デザインやプログラムといった「構造化された成果物」を生み出す対話において、テキストチャットの枠組みに閉じ込めておくことは、AIのポテンシャルをUIが制限している状態と言えるかもしれません。 - 「仕様」という名の思考停止
「たまたまプログラマーがテキストを使っているから」という現状に甘んじているのは、確かに開発側の怠慢という側面があるかもしれません。
アップロード機能があるということは、システム内部ではファイルを扱う仕組みが既に存在しています。
それにもかかわらず、出力側を「人間が見るための簡略化されたテキスト」に限定しているのは、AIを「清書してくれる秘書」程度にしか見ておらず、「実用的なアセットを生成するクリエイティブ・パートナー」として扱い切れていないことの現れかもしれません。
結論として 「ソースをアップロードできるなら、アウトプットもそのままダウンロードできるべき」というご意見は、AIを実務に組み込む全てのユーザーにとっての切実な願いだと思います。今のNotebookLMのような環境において、今回のような**「コードのサイレントな破壊」**を防ぐ唯一の抜本的な解決策は、まさにその「ダウンロード機能」の実装に他なりません。
ソースコードにあるような、18万回呼ばれる eval 関数
や、複雑なポリオミノの境界線を描画するロジック
を守るためにも、情報の完全性が保証されるUIへの進化が待たれます。
3.音声解説を聴いてみる
最初、ソースに2つを登録した状態で、音声解説(詳細:デフォルト)を作成して聴いてみると、ブログで書いてある内容に沿って概要を話してくれるので、何か別の単純作業をしながら、聞き流すのには向いています。
Youtubeにも解説動画があっても、その声質が気になるか、気にならないかで、ながら作業に向いているかが決まってくる気がします。ということは、内容は良いけど、耳障りな動画もNotebookLMのソースに登録して、音声解説を生成すればよいのか!
次に、6つのcppファイルと、自作したjavaファイルをソースに登録し、評論と議論を作成して聴いてみると、Qiita記事に書かれていない別の視点での改善のヒントとなるアイデアがいくつか聞くことができました。
これはチャットがプル型の情報収集とすると、反対のプッシュ型の情報提供という感じで、自分の意識のないことが得られるメリットは大きいと感じました。
4.チャットでの雑談
AIの知識量は計り知れないもので、おそらくリアルな世界では話題にできないことも、雑談できます。
例えば、たまたま浮動小数点の内部仕様の内容のときに、「そういえばIBMのメインフレームで独自仕様の128ビットの浮動小数点があったな」と言えば、その当時の仕様が出てくるのですな。
これはただの雑談であまり役には立たないですが、javaのソースの話をしているときに、むかしc言語ではこうだった、アセンブラではこうだったと振ってみれば、「どちらも同じ」「類似しているけどコンセプトが違う」「異なるもの」という回答が得られるのは、いろいろ疑問点が浮かぶ人にとってはAIチャットはよい相談相手となってくれます。
5.困った点
チャットにテキストで打って、テキストで返ってくるので、前述したソースファイルの配列の添字が抜けるだけでなく、「nnm」と書くと、「*」が消えて「nnm」と変わったりします。
手作業でテキストファイルに残していますが、後から見返すと「nnm」ってなんだ?となります。
一方で「メモに保存」することも可能ですが、メモが溜まってくると整理したいが、これが表示専用なのでイマイチです。
6.レポート出力
ずっとチャットでやり取りをメインで使っていたので、チャット機能でのアウトプットの不具合が気になってましたが、右ペインにレポート作成があるので、この時点の最終形のjavaファイルのソースをチェックし、cppファイルのソースのチェックを外して、レポート作成したみた。
これはいい!
世の中のソフトウェア開発の手法として、トップダウンとボトムアップ、ウォーターフォールとアジャイル、とざっくりあるとは思いますが、AHCのようなものがウォーターフォールのようにソースコードを書く前に詳細設計をするわけがなく、ある程度の方針はあって、トライアンドエラーで、一番よかったものが完成形なわけです。
ところが、最終形のソースコードが出来上がってから、ソースコードの読めない上司のための資料を作れだとか、引継ぎ資料を残せとか、勉強会の資料を作れっていうのは、消化試合みたいなものです。
まさにレポート出力すると、ソースコードが読めない上司のための資料をちゃっちゃと作ってくれるのでした。
あと、これを活用すると、ソースコードレビューで、スタイルとかミクロな部分のチェックになりがちですが、レポート出力で出された日本語の仕様を読んで、本来こんな動作だっけという点があれば、その部分のソースをチェックするような使い方もできるかも。
つまり、CIで今週修正されたソースファイルのユニットテストを定期実行して、劣化していないかチェックが走るように、ドキュメント生成を定期実行して、以前の内容と比較して、なんでここの仕様が変わっているんだと気づけば、それからソースファイルの詳細を確認すればよいかと。
7.レポート出力のダメなところ
Googleドキュメントにエクスポートというメニューを実行すると、Googleドキュメントに保存されますが、LaTexの記号がそのまま残ってしまって、残念。Genimiでも同じことをやり取りした覚えがあるけど、Googleドキュメント意外にこの記法に対応している形式にエクスポートできればよいのですけど。
Googleスプレッドシートにエクスポートも試しましたが、ただの用語集でした。
8.スライド資料(ベータ版)
こちらの方がもっとソースコードの読めない上司のための資料作成に向いています。
残念なことに、PDFファイルとパワーポイントファイルがダウンロードが出来るとはいえ、ただ画像を貼り付けているだけで、テキストの編集ができません。
エクスポートする前の状態で、変更アイコンがあり、「uint64_tをlongに変更」という指示を投げて作り直すくらいはできます。
9.現時点の感想
細かいことを言えば、AIが出力した品質はデタラメなものもあります。
それがまったく意味のないデジタルゴミかと言えば、世の中のタスクに意味のない資料作成に何ヵ月もかけて作成し、会議が終われば、その後、更新もされず誰も読まない資料が大量にストレージに溜まっていたりします。
それらのドラフト原稿を作らせると思えば、これほど効率の良いツールはないと思います。
10.一通り区切りがついた時点の感想
そういえば、NotebookLMを何日も開いていない。
例えば、cppの細かい仕様を知りたければ、いわゆるググるか、Geminiでもいいくらい。
最初の頃は、NotebookLMにソースを登録して、ここの部分はいつ初期化されるのか、等の質問をしたことはあったが、なんか回答が変で、自分でデバッグしてみると、理解した上で回答を読むと分かるけど、前提がまだない状態だと、逆によく分からなくなるような。
AIが普及する以前から、ちょろっと書いて動いたからテストせずに完成という人間もいたが、それとAIも同じようなものなのかな。
資料:レポート出力をコピーした未修正のテキスト
Qiitaならば、インラインで式を記述する記号で挟めば読める例
- \times は「$\times$」
- \leq は「$\leq$」
- \le は「$\le$」
- i_{max} は「$i_{max}$」
- N^2 は「$N^2$」
- \sum_{k=1}^{M} \mathbb{1}(\text{油田 } k \text{ がマス } (i, j) \text{ を占有している}) は「$\sum_{k=1}^{M} \mathbb{1}(\text{油田 } k \text{ がマス } (i, j) \text{ を占有している})$」
Polyomino Mining:技術要件定義書
- プロジェクト概要とシステム目的
本プロジェクト「Polyomino Mining」は、限られた観測リソースとノイズを含むデータを用いて、未知の地下構造(石油埋蔵分布)を効率的に特定する高度な推論システムの構築を目的とする。 エンジニアに求められる技術的マイルストーンは、統計的推定(ベイズ更新)と数理最適化(メタヒューリスティクス)を統合し、最小コストで石油の存在する全マスを特定するアルゴリズムの実装である。本仕様書は、コンテスト形式の問題を実システム開発の要件として再定義したものである。
開発システムが遵守すべき基本要件
- 対象領域: N \times N マスの島(10 \leq N \leq 20)。
- 主要ミッション: 石油埋蔵量 v(i, j) > 0 である全マスを特定し、最小コストで回答すること。
- システム制約:
- 最大操作回数:2N^2 回。
- 実行時間:3.0秒以内。
- メモリ:1024 MiB以内。
- 物理的対象: 事前に形状が既知である M 個のポリオミノ型油田(2 \le M \le 20)。
次に、探索アルゴリズムの基盤となる環境構成と、油田の幾何学的特性について定義する。
- 環境構成:グリッドと油田の幾何学的定義
探索空間の管理規約および油田の物理的制約を定義する。ポリオミノの重なりを考慮した「重ね合わせの状態」を正しくモデル化することが、計算効率の向上に直結する。
2.1. 座標系と配置の状態変数
- 座標管理: 左上のマスを (0,0) とし、下方向に i(行)、右方向に j(列)進む座標系を採用する。
- 配置の状態: 各油田 k (1 \le k \le M) は、ソースコード上で相対座標集合として与えられる。開発システムは、各油田の基準点(左上 (0,0))に対するオフセット (di_k, dj_k) を状態変数として管理する。
- 配置制約: 各油田は島からはみ出してはならない。すなわち、油田 k の最大座標を (i_{max}, j_{max}) とすると、オフセットは 0 \le di_k \le N - i_{max} - 1 および 0 \le dj_k \le N - j_{max} - 1 の範囲に限定される。
2.2. 油田(Oil Fields)の物理特性
- 連結性: 各油田は 1 \times 1 の正方形が辺を共有して連結したポリオミノ型である。
- 面積制約: 各油田 k の面積 d_k は 4 \le d_k \le N^2/M を満たす。これは探索空間における油田密度のバウンダリを規定する。
- 埋蔵量の定義: マス (i, j) における真の埋蔵量 v(i, j) は、そのマスを含む油田の数として定義される。 v(i, j) = \sum_{k=1}^{M} \mathbb{1}(\text{油田 } k \text{ がマス } (i, j) \text{ を占有している})
以上の静的な物理定義に基づき、システムは以下のインターフェースを通じて動的な情報収集を行う。
- 操作仕様とコスト構造の評価
システムは、精度とコストがトレードオフの関係にある3つの操作を使い分ける必要がある。特に「占い」操作におけるノイズの性質を理解し、コストパフォーマンスを最大化することが求められる。
操作種別 概要 コスト 取得情報の性質
掘削 (Drill) 1マスの調査 1 該当マスの正確な埋蔵量 v(i, j) を取得。
占い (Divine) 集合 S の調査 1/\sqrt{k} k マスの埋蔵量総和 v(S) の近似値(ノイズあり)。
推測 (Guess) 全埋蔵マスの特定 0 / 1 正解なら即終了(コスト0)。不正解ならコスト1を計上し継続。
戦略的洞察:コストとノイズの線形関係
「占い」において、標準偏差 \sigma は \sqrt{k} に比例して増大する一方、コストは 1/\sqrt{k} で減少する。これは「コストあたりの情報の不確実性(信号対雑音比)」が一定の割合でトレードオフされることを意味する。エンジニアは、広域の不確実性を効率的に減らすために、あえて大きな k を選択しノイズを許容するか、確信度を高めるために小さな k でコストをかけるかの動的な判断ロジックを実装すべきである。
- 正規分布に基づく誤差モデルの数理定義
占い操作で得られる「近似値」を統計的に処理するため、以下の正規分布モデルに基づく尤度計算ロジックを定義する。
4.1. 誤差パラメータと分布
- エラーパラメータ \epsilon: 0.01 \leq \epsilon \leq 0.2。
- 平均 \mu: \mu = (k-v(S))\epsilon + v(S)(1-\epsilon)
- 分散 \sigma^2: \sigma^2 = k\epsilon(1-\epsilon)
- \epsilon が大きいほど、観測値の平均 \mu は真値 v(S) から乖離(シフト)し、分布が広がる。
4.2. 観測確率 P(r | S) の計算
占い結果として整数 r が得られる確率は、正規分布 \mathcal{N}(\mu, \sigma^2) を区間 [r-0.5, r+0.5] で積分した面積となる。丸め処理(\text{round})と非負制約(\max(0, x))を考慮した実装は以下の通りとなる。
- r > 0 の場合: P(r|\mu, \sigma) = \int_{r-0.5}^{r+0.5} \mathcal{N}(x|\mu, \sigma^2) dx
- r = 0 の場合: P(0|\mu, \sigma) = \int_{-\infty}^{0.5} \mathcal{N}(x|\mu, \sigma^2) dx
この尤度計算は、複数の配置候補の中から真の配置パターンを絞り込む際のベイズ更新において中核となるロジックである。
- 評価指標とスコア算出ロジック
本システムは、以下の絶対コスト C に基づく二段階の評価体系を採用する。
絶対スコア (Absolute Score): ミッション成功時の支払総コストを C としたとき: \text{Score}_{\text{abs}} = \text{round}(10^6 \times \max(C, 1/N)) ※ 失敗、あるいは 2N^2 回超過時は 10^9。「小さいほど優秀」。
相対評価スコア (Relative Score): 全参加者の最小絶対スコアに対する比率: \text{Score}_{\text{rel}} = \text{round}\left(10^9 \times \frac{\text{全参加者中の最小絶対スコア}}{\text{自身の絶対スコア}}\right) ※ 「大きいほど優秀」。
- 実装に向けたアルゴリズム検討事項
本プロジェクトの核心は、膨大な配置の組み合わせ(N \approx 20, M \approx 20)の中から、尤度の高い配置パターンを効率的にサンプリングすることにある。
6.1. データ構造と高速化戦略
- ビットセット(BitSet)の活用: グリッドは最大 400 マスであるため、各油田の占有領域をビットセットで管理し、論理演算(OR/AND)による埋蔵量計算や重複判定の高速化を図る。
- ** coverage マスクの事前計算:** 各油田 k について、島内の全可能オフセット (di, dj) における被覆マス集合を事前に計算しテーブル化しておく。これにより、尤度計算時のループ処理を排除する。
6.2. 開発の優先順位(エンジニア視点)
- 尤度サンプリングエンジンの構築: 焼きなまし法(Simulated Annealing)またはマルコフ連鎖モンテカルロ法(MCMC)を用いて、現在の観測データに基づく事後確率 P(x|R) が高い配置候補集合(Pool)を生成・維持する。
- Zobrist Hashing による状態管理: 配置パターンのハッシュ値を(油田ID, オフセット (di, dj))の排他的論理和で定義し、計算済みの尤度をキャッシュすることで、重複計算を回避する。
- 相互情報量(Mutual Information)によるクエリ最適化: 次の占い領域 S を選定する際、各候補領域がもたらす「期待情報量(エントロピーの減少)」をコスト 1/\sqrt{k} で除した値を最大化する領域を選択する。
- 終了判定の厳密化: 現在の Pool 内で最も有力な配置の事後確率が一定の閾値(例:0.8〜0.9)を超えた時点で Guess を実行する。ただし M が大きい環境ではノイズ耐性を高めるため、確信度が低い場合は追加の占いや掘削を優先させる。
単なる全探索は計算量的に不可能であり、本要件定義に基づく「統計的サンプリング」と「情報利得の最適化」を統合した推論エンジンの実装が、最高スコアへの最短経路である。