プログラミング
NoiseLang: N = 5 がディラックのデルタ関数となる場所
NoiseLang: Where N = 5 is a Dirac delta (manualmeida.dev)
要約
NoiseLangは、すべての値が確率分布であるという単一のアイデアに基づいた新しいプログラミング言語です。定数も単一の値に集中した分布(ディラックのデルタ関数)として扱われ、これにより定数と確率変数が同じオブジェクトとして扱われ、演算子も分布から分布へのマッピングとなります。この言語は、複雑な確率計算を簡潔に記述し、モンテカルロシミュレーションを効率的に実行することを目指しています。
全文翻訳
電気通信の学位を取得中に、信号とノイズに関するコースを受講しました。期待値、分散、2つの確率変数が特定の領域に収まる確率など、多くの夜を確率を手書きして過ごしました。コンピューターで実行しようとすると、常にひどいものでした。多くの定型コードが必要でした。その願いがNoiseLangになりました。約9年前に始めましたが、完成しませんでした。最近になって、AIツールと、以前一人で構築できたものよりもはるかに野心的なもののおかげで、再び取り組むようになりました。すべては分布である言語全体は1つのアイデアに基づいています。それは、すべての値が確率分布であるということです。通常の数値はディラックのスパイク、つまり単一の値にすべての重みを持つ分布です。定数と確率変数は同じ種類のオブジェクトであるため、言語内のすべての演算子は分布から分布へとマッピングします。名前は常に1つの固定ノードを参照します。これは、数学のページ全体でXが同じXであるのと同じです。したがって、X + Xは2Xであり、X - Xは正確に0です。変数の独立性を望む場合は、個別のドローを記述します。つまり、複数回〜を使用するか、〜[N]を使用してN個の独立な変数をベクトルにドローします。X ~ unif_int(1, 6)Y ~ unif_int(1, 6)X + Y # 2つの独立なサイコロ、実際の2d6分布結果を要求するまで何も実行されません。例えば、P(X + Y < 10) のような場合、ランタイムは数百万回のシミュレーション(利用可能な場合はすべてのコアで)を実行し、標準誤差が付いた推定値を返します。Bday = unif_int(1, 365)days ~[23] Bday # 部屋にいる23人P(has_duplicates(days)) # 誕生日問題、約0.507説明するよりも見る方がはるかに簡単なので、クールなデモを作成しました!すべての値は分布ですA = 5D1 ~ unif_int(1, 6)D2 ~ unif_int(1, 6)S = A + D1 + D2E(S)は0をドローしますA ≈ — 図1. 4つのステップを経た同じヒストグラム:定数は単一のスパイク、チルダはそれをサイコロに広げ、2つのサイコロを加えるとベルカーブに近づき、クエリは平均値を読み取ります。数値は分布ですA = 5は通常の定数のように見えますが、Noiseはそれをすべてのドローが5に着地する確率分布として認識します。統計学者はこれをディラックのデルタ関数、単一の無限に細いスパイクと呼びます。チルダはそれを広げますD1 ~ unif_int(1, 6)は、6つの面がすべて等しく可能性のある、公正なサイコロを束縛します。スパイクは6つの平坦なバーに広がります。したがって、D1は不確実ですが、他の変数と同じように記述します。それらを結合するとベルが現れます定数と2つの独立なサイコロをS = A + D1 + D2として追加します。平坦な形状は畳み込まれて12でピークを持つ三角形になり、すでにベルに近づいており、さらにいくつか追加すると真のガウス分布に鋭くなります。それは中心極限定理が無料で現れているのです!クエリは数百万回のドローを収縮させます結果を要求するまで何も実行されません。E(S)、期待値は、数百万回のロールを平均して1つの数値にするモンテカルロパスを起動し、大数の法則により、実行中の平均は12に落ち着きます。あなたは数行の数学を書き、専門家レベルのカーネルが下で実行されました。なぜ9年間放置されたのか設計は決して難しい部分ではありませんでした。なぜなら、この言語のパーサーとツリーウォーキングインタープリターは週末の作業だからです。問題はそれ以外すべてでした。単純なインタープリターではなく、効率的なモンテカルロランタイム、条件付きベイズ推論、その他を書くことでした。現在のバージョンはコンパイラ、JIT(素晴らしいCraneliftを使用)、WASMバックエンド、そして注意深く数値コードを積み重ねたものであり、かわいい週末プロジェクトとしては手の届かないところにありました。エージェントを使った野心的なバージョンの構築私の日々の仕事やサイドプロジェクトで、今日のAIエージェントができることの境界を実験しています。例えば、15年前に古いObjective-Cで書いたゲームを、最新のゲームエンジンに移植しています(比較的成功しています)。NoiseLandで、AIはJIT部分、ランタイム部分、数値部分を構築するのに優れていますが、優れた言語設計のアイデアを思いつくのは苦手です。多くの場合、異なる目的のために既存の言語機能をオーバーライドしたり、非直交な機能のために異なる構文を考え出したりします。図2. この記事に埋め込まれたインラインGLSLシェーダーによってライブで描画された、密度曲線の下に集まるモンテカルロサンプルのフィールド。1つのIR、3つのバックエンド内部では、〜と分布コンストラクタがRvGraphと呼ばれる追記専用DAGを構築します。このグラフは単一の真実の情報源であり、その後3つの異なるコードパスに変換されます:どこでも動作し、正しさのオラクルとして機能するカラムバッチインタープリター;式全体を1つのネイティブカーネルに融合するCranelift JIT;ブラウザで同じことを行うWASMエミッタ。フォールバックフォールバックX ~ unif(1, 6)RvGraphバッチインタープリターCranelift JITWASMエミッタ1つの共有モジュールがグラフの意味を定義するため、2つのコードジェネレータはスリムに保たれ、乖離することはありません。バックエンドが正常にコンパイルできないものはすべてインタープリターにフォールバックし、結果はバックエンドやコア数間で同一になります。すべてのテストは3つのコードパスすべてで実行され、ビット単位で同一であることが比較されます。モンテカルロループを安価にするパフォーマンス作業はすべて1つのループに関するものです:数百万のサンプルをドローし、各サンプルで式を評価し、結果を削減します。少数のテクニックがその大部分を担っており、結果を決定論的に保ちながら(それが難しい部分でした)。カーネル融合はすべての途中値をレジスタに保持するため、算術的に重い式はレジスタに留まります。PRNG(xoshiro256++)はカーネルにコンパイルされ、ln、sin、cosはインライン多項式近似になり、カーネルを2倍高速化します。私のお気に入りのトリックはRNGにあります。乱数を生成することはシリアルな依存関係チェーンなので、それに逆らうのではなく、カーネルは一度に4つの独立したストリームを実行し、アウトオブオーダーコアにそれらをオーバーラップさせます。このトリックは、手書きのSIMDカーネルを上回りました!私の14コアM4 Proでは、1行のP(...)は毎秒約58億サンプルを維持し、1コアから全コアへのスケーリングは約9.6倍です。コアあたりでは、生成されたカーネルはLLVMでコンパイルされた手書きのRustの約1.15倍の速度で実行されます。同じ融合ループがWASMとしてエミットされ、V8内でネイティブ速度の約半分から3分の2で実行されます。モンテカルロでπを推定するプレイグラウンドで ↗X ~ rand::unif(-1, 1)Y ~ rand::unif(-1, 1)C = X^2 + Y^2 < 14 * P(C)ダーツ0内側0π ≈ — 図4. モンテカルロπ。円は正方形のπ/4をカバーするため、緑色の部分の4倍がダーツが集まるにつれてπに収束します。2つのランダムドローこれは以前と同じ〜ですが、2回使用されます。X ~ unif(-1, 1)とY ~ unif(-1, 1)はそれぞれ[-1, 1]のどこかの数値をドローし、それらを合わせて正方形内のランダムな点を拾います。はい/いいえの質問を1つするC = X² + Y² < 1は、点が単位円の内側にある場合に正確に真となります。Noiseでは、その比較自体が確率変数、つまり各ドローで真または偽に着地するベルヌーイ分布です。次にダーツを投げる各ダーツは、(X, Y)の1回のドローです。点が円の内側にある場合は緑色、そうでない場合は灰色になります。一様ドローはどの点も他の点よりも優先しないため、それらは均等に散らばります。部分の4倍がπ円は正方形の面積のπ/4をカバーするため、緑色の部分はπ/4の周りをホバリングし、それにより4 * P(C)はπの推定値となります。ダーツを多く投げれば投げるほど、推定値はシャープになります。Noiseはどこに位置するかNoiseLangはトイ言語であり、おそらく真面目なことには使用すべきではありません。しかし、大学時代にこの言語が存在してほしかったと思います。言語オタクにとっては、フォワードモンテカルロ、式ベース、拒否ベースの条件付けを備えた、小さく静的な確率変数代数です。NumPyやStanと比較してどうですか?と尋ねるかもしれません。NumPyはシミュレーションを自分で書く必要があり、Stanはモデルを宣言してサンプラーを待つ必要があります。Noiseは、確率を数学として書き、バックグラウンドでモンテカルロを実行して答えを得ることができます。NoiseNumPyStanPyMCそれは何RV代数+モンテカルロ配列数値計算宣言型ベイズモデリングPythonでのベイズモデリングコア抽象化すべて