データ並列演算子を備えた完全な関数型言語を使用してどのアルゴリズムを表現できますか?


11

データ型のみが数値スカラーと配列の任意のネストである関数型プログラミング言語を想像してください。この言語には、無制限の反復の手段がないため、次のものは許可されません。

  • 明示的なループ(副作用なしではあまり使用されません)
  • 再帰
  • 任意のファーストクラス関数(yコンビネーターなし)

ただし、言語には次のものがあります。

  • トップレベル関数
  • レキシカルスコープのletバインディング
  • 分岐制御フロー
  • 一般的なスカラー数学および論理関数
  • fill(n、x)のようないくつかの単純な配列コンストラクターは、同じ値xを持つn要素の配列を作成します
  • 最も重要なこと:並列構造化反復(map、reduce、scan、all-pairsなど)を実行する高次演算子の制限されたセット。

データ並列演算子をより具体的にするには:

  • y = map(f、x)=> y [i] = f [i]
  • y = reduce(f、a、x)=> y = f(a、f(y [p [0]]、f(y [p [1]]、...)))いくつかの順列p
  • y = scan(f、a、x)=> y [i] = reduce(f、a、y [0 ... i-1])
  • y = allpairs(f、x、y)=> y [i、j] = f(x [i]、y [j])

他の演算子を使用することもできますが、修飾するには多項式の実行時間を持ち、データ並列計算の合理的なモデルの下で実装可能であり、多くても多項式空間を使用する必要があります。

以下のような、この言語では表現できないいくつかの構成要素があることは明らかです。

while f(x) > tol:
    x <- update(x)   

このシステムで何を表現できますか?FPの検索問題のみに制限されていますか?すべての多項式時間アルゴリズムをキャプチャできますか?また、このクラスには最小限の演算子セットがありますか?

回答:


7

これらのアイデアを真剣に受け止めた古いプログラミング言語NESLご覧ください。この言語は、コレクション、基本的にはリストとリストのリストなどの操作に基づいていますが、トリッキーなエンコーディングを介して、ツリーとグラフも考慮されたと思います。そのプロジェクト(1990年代半ば)で行われた研究のいくつかは、あなたの質問に答えるのに役立ちます。博士論文(書籍として入手可能)Guy E. Blelloch。データ並列コンピューティングのベクトルモデル。MIT Press、1990がいくつかの答えを提供するかもしれません。私がそれを見たのはしばらく前のことでした。

Bird-Meertens Formalism(BMF)で行われた作業も、言語Charityと同様にこのカテゴリに分類されます。チャリティウィキペディアのページから、言語はチューリング完全ではないが、アッカーマンの機能を表現できると言っています。つまり、それは原始的な再帰以上のものです。BMFとCharityの両方には、フォールドやスキャン(異形、アナモルフィズムなど)のような演算子が含まれており、カテゴリ理論にルーツがあります。

私が短く、不正確な答えは、あなたがかなりたくさん表現できるということです。


1
NESLは完全な言語ではありません。
Per Vognsen

私はしばらくの間NESLを表面的に知っていましたが、初めてBlellochの論文の1つを詳細に読んだだけです。ヒントをありがとう。NESLは、上記で説明した言語とかなり似ていますが、Per Vognsenが気づいたように、再帰を許可している点が異なります。
アレックスルービン

Blellochのプリミティブ演算子の選択にも興味があります:map、dist(私は 'fill'と呼んだものと同じと思います)、length、array-read、array-write、scan、partition、flatten。NESLのプリミティブは「完全」ですか、またはこれらを使用して効率的に表現できないデータ並列実装で他の操作がありますか?
アレックスルービン

2
再帰を削除すると、特に折り畳みなどを考慮する場合は、かなり表現力のある言語になります。BMFとそれに続く作業を見ると、より興味深いかもしれません。申し訳ありませんが、この分野では最新ではありません。
デイブクラーク

7

私の他の答えは、現状の言語の欠陥を指摘しました。この回答では、言語全体での折り畳みと展開の共存に関する問題について詳しく説明します。次に、解決策を提案し、Pのすべての問題(さらに多くの問題)がこの拡張言語で解決できることを示します。

合計言語での折りたたみはリストを消費します:

fold :: (a -> b -> b) -> b -> List a -> b

合計言語で展開すると、ストリームが生成されますが、これらは潜在的に無制限です。

unfold :: (b -> Maybe (a, b)) -> b -> Stream a

残念ながら、リストとストリームは異なる世界に存在するため、これらの演算子は構成できません。部分的な対応が必要です。

stream :: List a -> Stream a
list :: Int -> Stream a -> List a

ストリーム演算子は、リストを制限されたストリームに埋め込みます。リスト関数は、最初のn個の要素(または、ストリームがより早く終了する場合はそれより少ない要素)をリストに抽出します。したがって、次の方程式があります。

for all xs :: List a, xs == list (length xs) (stream xs)

効率の最適化として、中間データ構造としてストリームを完全にカットできます。

unfoldList :: Int -> (b -> Maybe (a, b)) -> b -> List a

ここで、(これは元の質問ですでに暗示されている他の演算子とともに)多項式時間アルゴリズムをシミュレートできることの証明をスケッチします。

定義上、チューリングマシンMと多項式pがある場合、言語LはPにあり、Lのxのメンバーシップは、Mを最大p(n)回実行することで決定できます(n = | x |)。標準の引数により、マシンのテープが無限であっても、反復kでのマシンのテープの状態は、最大2k + 1の長さのリストでエンコードできます。

これは、Mの遷移をリストからリストへの関数として表すという考え方です。遷移関数を使用して初期状態を展開することにより、マシンの実行が行われます。これにより、リストのストリームが生成されます。LがPにあるという仮定は、ストリームをp(n)要素以上調べる必要がないことを意味します。したがってlist p(n)、有限リストを取得するために展開を構成できます。最後に、それを折り返して、決定問題への答えがyesまたはnoであったかどうかを確認します。

より一般的には、これは、言語で計算可能な関数によって終了時間を制限できるアルゴリズムがある場合はいつでも、それをシミュレートできることを示しています。これはまた、アッカーマン関数のようなものがシミュレートできない理由を示唆しています。それはそれ自身の限界なので、鶏と卵の問題があります。


4

それは非常にぎこちない言語です。階乗関数をプログラミングしてみてください:

fact 0 = 1
fact n = n * fact (n-1)

問題は、言語には折り畳みのみがあり、展開はないことです。階乗を表現する自然な方法は、nの展開をリスト[1、2、...、n]に構成し、乗算しながらそれを分解する折り畳みです。

この特定の言語、または一般的な関数型プログラミング全般に本当に興味がありますか?あなたの言語がせいぜい多項式時間アルゴリズムを表現できることは明らかです。システムF(多相ラムダ計算)は、アッカーマン関数のようなモンスターを簡単に表現できます。多項式時間アルゴリズムに関心がある場合でも、それらを自然に表現するために頻繁に超多項式エルボルームが必要です。

編集:Daveが指摘するように、NESLは独創的な機能的データ並列プログラミング言語の1つですが、全体からはかけ離れています(試してさえいません)。APLファミリーには進化の並行した軌跡があり、完全な代数サブセットがあります(固定小数点演算子を避けます)。質問の焦点が全体性である場合、David Turnerはこの分野でいくつかの優れた論文を書いていますが、特にデータ並列プログラミングについては書いていません。


申し訳ありませんが、展開演算子の欠如は私の側の見落としです...私は1つを追加するつもりでしたが、それを投稿に入れるのを忘れました。この特定の言語には必ずしも興味がありませんが、むしろデータ並列計算の表現力と限界に興味があります。
アレックスルービン

展開は、配列値ではなく、当然ストリーム値です。これは、完全に厳密な言語でのコアカージョンの基本的な問題です。
ヴォーグセンごと10
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.