コンピュータサイエンスにおいて、数値のシーケンスx 0、x 1、x 2、 ...の接頭辞和、累積和、包括的スキャン、または単にスキャンとは、入力シーケンスの接頭辞(累積合計)の合計である、別の数値のシーケンスy 0、y 1、y 2 、 ...のことです。
プレフィックス和は、逐次計算モデルでは、式y i = y i − 1 + x iを使用して各出力値を順序通りに計算することで簡単に計算できます。しかし、計算が容易であるにもかかわらず、プレフィックス和は、カウントソートなどの特定のアルゴリズムで有用なプリミティブであり、[ 1 ] [ 2 ]関数型プログラミング言語のscan高階関数 の基礎を形成します。プレフィックス和は、並列アルゴリズムでも、解決すべきテスト問題として、また他の並列アルゴリズムのサブルーチンとして使用できる有用なプリミティブとして、広く研究されています。[ 3 ] [ 4 ] [ 5 ]
抽象的に言えば、接頭辞和は二項結合演算子⊕のみを必要とするため、点の十分に分離されたペア分解の計算から文字列処理まで、多くのアプリケーションで役立ちます。[ 6 ] [ 7 ]
数学的には、接頭辞和をとる演算は有限数列から無限数列へと一般化できます。その場合、接頭辞和は数列の部分和として知られています。接頭辞和または部分和は、有限数列または無限数列のベクトル空間上の線形演算子を形成し、その逆演算子は有限差分演算子です。
In functional programming terms, the prefix sum may be generalized to any binary operation (not just the addition operation); the higher order function resulting from this generalization is called a scan, and it is closely related to the fold operation. Both the scan and the fold operations apply the given binary operation to the same sequence of values, but differ in that the scan returns the whole sequence of results from the binary operation, whereas the fold returns only the final result. For instance, the sequence of factorial numbers may be generated by a scan of the natural numbers using multiplication instead of addition:
Programming language and library implementations of scan may be either inclusive or exclusive. An inclusive scan includes input xi when computing output yi (i.e., ) while an exclusive scan does not (i.e., ). In the latter case, implementations either leave y0 undefined or accept a separate "x−1" value with which to seed the scan. Either type of scan can be transformed into the other: an inclusive scan can be transformed into an exclusive scan by shifting the array produced by the scan right by one element and inserting the identity value at the left of the array. Conversely, an exclusive scan be transformed into an inclusive scan by shifting the array produced by the scan left and inserting the sum of the last element of the scan and the last element of the input array at the right of the array.[8]
The following table lists examples of the inclusive and exclusive scan functions provided by a few programming languages and libraries:
The directive-based OpenMP parallel programming model supports both inclusive and exclusive scan support beginning with Version 5.0.
There are two key algorithms for computing a prefix sum in parallel. The first offers a shorter span and more parallelism but is not work-efficient. The second is work-efficient but requires double the span and offers less parallelism. These are presented in turn below.

HillisとSteeleは、以下の並列プレフィックス和アルゴリズムを提示している。[ 9 ]
i <- 0 から log 2 ( n )まで実行し、 j <- 0 からn - 1まで並列に実行します。j < 2 iの場合、x i +1 j < - x i jとなります。そうでない場合、 x i +1 j <- x i j + x i j - 2 iとなります。
上記では、表記法は、タイムステップiにおける配列xのj番目の要素の値を意味します。
単一のプロセッサでは、このアルゴリズムはO ( n log n )時間で実行されます。[ 10 ]ただし、マシンに少なくともn 個のプロセッサがあり、内側のループを並列に実行できる場合、アルゴリズム全体は、外側のループの反復回数であるO (log n )時間で実行されます。

作業効率の良い並列プレフィックス和は、以下の手順で計算できます。[ 3 ] [ 11 ] [ 12 ]
入力シーケンスがnステップの場合、再帰はO (log n )の深さまで継続し、これはこのアルゴリズムの並列実行時間の上限でもあります。アルゴリズムのステップ数はO ( n )であり、プロセッサ数よりも要素数が多いアルゴリズムのラウンドで各プロセッサに複数のインデックスを割り当てることにより、 O ( n /log n )個のプロセッサを持つ並列ランダムアクセス マシン上で漸近的な速度低下なしに実装できます。[ 3 ]
前述の各アルゴリズムは、O (log n )の時間で実行されます。ただし、前者は正確にlog 2 nステップかかるのに対し、後者は2 log 2 n − 2 ステップかかります。図示した16個の入力の例では、アルゴリズム 1は12方向並列(49単位の作業が4のスパンで分割)であるのに対し、アルゴリズム 2は4方向並列(26単位の作業が6のスパンで分割)です。しかし、アルゴリズム 2は作業効率が高く、 逐次アルゴリズムに必要な作業量の定数倍(2)しか実行しません。一方、アルゴリズム 1は作業効率が低く、逐次処理に必要な作業量よりも漸近的に多くの作業(対数倍)を実行します。したがって、 並列処理が豊富な場合はアルゴリズム1の方がパフォーマンスが良い可能性が高く、 並列処理が限られている場合はアルゴリズム2の方がパフォーマンスが良い可能性が高いです。
接頭辞和の並列アルゴリズムは、結合法則を満たす二項演算の他のスキャン操作に一般化できる場合が多く、[ 3 ] [ 4 ]また、 GPUなどの最新の並列ハードウェア上で効率的に計算することもできます。[ 13 ]多パラメータ接頭辞和の計算専用の機能ユニットをハードウェアに構築するというアイデアは、Uzi Vishkinによって特許取得されました。[ 14 ]
多くの並列実装では、2段階の手順が採用されています。まず、各処理ユニットで最初の処理において部分的なプレフィックス和が計算されます。次に、これらの部分和のプレフィックス和が計算され、既知のプレフィックスを初期値として、2回目の処理のために処理ユニットにブロードキャストされます。漸近的には、この方法は項目ごとに約2回の読み出し操作と1回の書き込み操作を必要とします。
並列プレフィックス和アルゴリズムの実装は、他の並列アルゴリズムと同様に、プラットフォームの並列化アーキテクチャを考慮する必要があります。具体的には、共有メモリ上で動作するプラットフォームに適したアルゴリズムと、プロセス間通信の唯一の手段としてメッセージパッシングを使用する分散メモリを使用するプラットフォームに適したアルゴリズムが複数存在します。
以下のアルゴリズムは共有メモリマシンモデルを前提としており、すべての処理要素(PE)が同じメモリにアクセスできます。このアルゴリズムのバージョンは、マルチコア標準テンプレートライブラリ(MCSTL)[ 15 ] [ 16 ]に実装されています。MCSTLは、さまざまなアルゴリズムの並列計算用に調整されたバージョンを提供するC++標準テンプレートライブラリの並列実装です。
n個のデータ要素に対するプレフィックス和をp個の処理要素で同時に計算するために、データは分割されます。ブロック、それぞれに要素(簡略化のため、nを分割します)。アルゴリズムはデータを分割しますが、ブロックでは、一度に並列実行される処理要素はp個のみです。
最初のスイープでは、各PEは自身のブロックのローカルプレフィックス和を計算します。最後のブロックは計算する必要はありません。なぜなら、これらのプレフィックス和は後続のブロックのプレフィックス和に対するオフセットとしてのみ計算され、最後のブロックは定義上後続しないからです。
各ブロックの最後の位置に格納されているp個のオフセットは、それぞれ独自のプレフィックス和として累積され、後続の位置に格納されます。pが小さい場合は、これを順次実行する方が高速ですが、pが大きい場合は、このステップを並列で実行することも可能です。
2回目のスキャンが実行されます。今回は、先行するブロックのオフセットを考慮する必要がないため、最初のブロックは処理する必要はありません。ただし、このスキャンでは代わりに最後のブロックが含まれ、各ブロックのプレフィックス和は、前回のスキャンで計算されたプレフィックス和ブロックのオフセットを考慮して計算されます。
function prefix_sum ( elements ) { n := size ( elements ) p :=処理する要素の数prefix_sum := [ 0. . .0 ]サイズnの並列i = 0からp - 1 { // i := 現在のPEのインデックスfrom j = i * n / ( p + 1 ) to ( i + 1 ) * n / ( p + 1 ) - 1 do { // これはローカル ブロックのプレフィックス サムのみを保存しますstore_prefix_sum_with_offset_in ( elements , 0 , prefix_sum ) } } x = 0 for i = 1 to p { // ブロックの合計のシリアル累積x += prefix_sum [ i * n / ( p + 1 ) - 1 ] // 最初の p ブロックのプレフィックス サムを構築 prefix_sum [ i * n / ( p + 1 ) ] = x // 2 番目のスイープでオフセットとして使用するために結果を保存します} do parallel i = 1 to p { // i := 現在の PE のインデックスfrom j = i * n / ( p + 1 ) to ( i + 1 ) * n / ( p + 1 ) ) - 1 do { offset := prefix_sum [ i * n / ( p + 1 )] // 前のブロックの合計をオフセットとして、プレフィックス合計を計算しますstore_prefix_sum_with_offset_in ( elements , offset , prefix_sum ) } } return prefix_sum }改善点:ブロック数が多すぎて、単一のプロセッサを配置して逐次処理に時間がかかる場合、Hillis and Steeleアルゴリズムを使用して第2フェーズを高速化できます。
ハイパーキューブプレフィックスサムアルゴリズム[ 17 ]は分散メモリプラットフォームによく適応しており、処理要素間のメッセージ交換で動作します。アルゴリズムに参加するプロセッサ要素(PE)の数は、d次元超立方体の角の数に等しい。

アルゴリズム全体を通して、各PEは仮想的なハイパーキューブの頂点とみなされ、そのハイパーキューブ内の、自身までのすべての要素のプレフィックス和σとプレフィックス和x(PE間の順序付けられたインデックスによる)の両方に関する情報が与えられます。
d次元の超立方体では角にPEがある場合、アルゴリズムをd回繰り返す必要があります。ゼロ次元ハイパーキューブは、1つのd次元ハイパーキューブに統合されます。異なるハイパーキューブ内の隣接する2つのPEのσを1つの通信ステップで双方向に交換できる双方向通信モデルを仮定すると、これは次のことを意味します。コミュニケーション関連のスタートアップ企業。
i : =自身のプロセッサ要素( PE )のインデックスm : =このPEのローカル要素のプレフィックス和d : =ハイパーキューブの次元数x = m ; // 不変: 現在のサブキューブ内のこの PE までの接頭辞和σ = m ; // 不変: 現在のサブキューブ内のすべての要素の接頭辞和for ( k = 0 ; k <= d -1 ; k ++ ) { y = σ @ PE ( i xor 2 ^ k ) // 次元 k に沿った反対側のサブキューブのプレフィックス合計を取得しますσ = σ + y // 両方のサブキューブのプレフィックス合計を集計しますif ( i & 2 ^ k ) { x = x + y // この PE がより高いインデックスである場合のみ、他のサブキューブからのプレフィックス合計を集計します。} }パイプラインバイナリツリーアルゴリズム[ 18 ]は、分散メモリプラットフォーム向けの別のアルゴリズムであり、特に大きなメッセージサイズに適しています。
ハイパーキューブアルゴリズムと同様に、このアルゴリズムも特殊な通信構造を前提としています。処理要素(PE)は、 PE内のインデックスに従って中置記数法で番号付けされた二分木(例えばフィボナッチ木)に仮想的に配置されます。このような木構造における通信は、常に親ノードと子ノード間で行われます。
中置記法により、任意の PE jに対して、その左部分木で到達可能なすべてのノードのインデックスが保証されます。jより小さく、インデックスは右サブツリー内のすべてのノードのうち、jより大きいものが存在する。PE jが左の子である場合、親のインデックスは PE jのサブツリー内のどのインデックスよりも大きく、PE jが右の子である場合は小さくなる。これにより、次の推論が可能になる。

サブツリーローカルプレフィックス合計と全プレフィックス合計の違いに注意してください。2、3、4番目の点から循環依存が形成されるように思われるかもしれませんが、そうではありません。下位レベルの PE は、自身の全プレフィックス合計を計算するために上位レベルの PE の全プレフィックス合計を必要とする場合がありますが、上位レベルの PE は、自身の全プレフィックス合計を計算するためにサブツリーローカルプレフィックス合計のみを必要とします。最上位レベルのノードであるルートノードは、自身のプレフィックス合計を計算するために左サブツリーのローカルプレフィックス合計のみを必要とします。PE 0からルート PE までのパス上の各 PE は、自身のプレフィックス合計を計算するために左サブツリーのローカルプレフィックス合計のみを必要としますが、PE p-1 (最後の PE) から PEルートまでのパス上のすべてのノードは、自身の全プレフィックス合計を計算するために親の全プレフィックス合計を必要とします。
これにより、2段階のアルゴリズムが導き出される。
アルゴリズムは各PEで並列実行され、PEは子/親からパケットを受け取るまで受信時にブロックされることに注意してください。
k := PE m のメッセージm内のパケット数@ { left , right , parent , this } : = //異なるPEのメッセージx = m @ this// 上向きフェーズ - j = 0からk - 1までのサブツリーローカルプレフィックス合計を計算します。// パイプライン処理: メッセージの各パケットについて、hasLeftChildの場合: blocking receive m [ j ] @ left // これにより、ローカル m[j] が受信された m[j] に置き換えられます// 下位インデックス PE からの包括的なローカルプレフィックス合計を集約しますx [ j ] = m [ j ] ⨁ x [ j ]if hasRightChild : blocking receive m [ j ] @ right // 右の子はインデックスが高いPEなので、m[j]をローカルのプレフィックス合計に集約しないsend x [ j ] ⨁ m [ j ] to parent else : send x [ j ] to parent// j = 0からk - 1 までの下降フェーズ: m [ j ] @ this = 0hasParentの場合:ブロッキング受信m [ j ] @ parent // 左の子の場合、m[j] は親の排他的プレフィックス和、右の子の場合、包含的プレフィックス和x [ j ] = m [ j ] ⨁ x [ j ] send m [ j ] to left // この PE または左サブツリー内の任意の PE より小さいすべての PE の合計プレフィックス和send x [ j ] to right // この PE より小さいか等しいすべての PE の合計プレフィックス和長さnのメッセージm をk 個のパケットに分割でき、対応する各メッセージ パケットに対して演算子 ⨁ を個別に使用できる場合、パイプライン処理が可能です。[ 18 ]
アルゴリズムをパイプライン処理なしで使用する場合、バイナリツリーの2つのレベル(送信PEと受信PE)のみが常に動作し、他のすべてのPEは待機状態になります。p個の処理要素があり、バランスのとれたバイナリツリーを使用する場合、ツリーは次のようになります。レベル、パスの長さにしたがってこれは上昇フェーズ中の非並列通信操作の最大数を表し、同様に下降パス上の通信も制限されます。スタートアップ。通信開始時間を想定するとバイト単位の送信時間は上昇および下降フェーズは、パイプライン処理を行わないシナリオの場合。
k個のパケットに分割すると、それぞれのサイズはそしてそれらを別々に送信すると、最初のパケットはまだ伝播されるローカルプレフィックスサムの一部として、これは最後のパケットでも再び発生します。しかし、その間、パス上のすべてのPEは並列に動作でき、3番目の通信操作(左受信、右受信、親への送信)ごとにパケットが次のレベルに送信されるため、1つのフェーズは通信業務と両方のフェーズを合わせて必要とするこれは大きなメッセージサイズnに対して有利です。
このアルゴリズムは、全二重通信または電話モデル通信を利用し、上昇フェーズと下降フェーズを重ね合わせることでさらに最適化できる。[ 18 ]
データセットが動的に更新される場合、フェンウィックツリーデータ構造に格納されることがあります。この構造では、任意の個々のプレフィックス合計値のルックアップと、任意の配列値の変更を、操作ごとに対数時間で行うことができます。[ 19 ]ただし、1982 年の論文[ 20 ]では、フェンウィックツリーと重複すると思われる部分合計ツリーと呼ばれるデータ構造が提示されています (セクション 5.1 を参照)。1982 年当時は、プレフィックス合計という用語は今日ほど一般的ではありませんでした。
高次元配列の場合、合計面積テーブルは、任意の矩形サブ配列の合計を計算するためのプレフィックス合計に基づくデータ構造を提供します。これは、画像畳み込み演算において有用なプリミティブとなり得ます。[ 21 ]
計数ソートは、キー頻度のヒストグラムのプレフィックス和を使用して、ソートされた出力配列内の各キーの位置を計算する整数ソートアルゴリズムです。キーの整数値が項目の数より小さい場合は線形時間で実行され、大きさの制約が少ない整数をソートするための高速アルゴリズムである基数ソートの一部としてよく使用されます。[ 1 ]
リストランキングとは、連結リストを同じ項目のシーケンスを表す配列に変換する問題であり、1, 1, 1, ... のシーケンスに対してプレフィックス和を計算し、各項目をそのプレフィックス和の値によって与えられる配列の位置にマッピングすることとして考えることができます。リストランキング、プレフィックス和、およびオイラーツアーを組み合わせることで、木構造に関する多くの重要な問題を効率的な並列アルゴリズムで解決できます。[ 4 ]
並列プレフィックス和アルゴリズムの初期の応用例は、 2 つのnビットのバイナリ数を加算できるブール回路であるバイナリ加算器の設計でした。この応用では、加算のキャリービットのシーケンスは、入力ビットのペアのシーケンスに対するスキャン操作として表現でき、多数決関数を使用して前のキャリーをこれらの 2 つのビットと組み合わせます。出力数の各ビットは、対応するキャリービットとの 2 つの入力ビットの排他的論理和として見つけることができます。並列プレフィックス和アルゴリズムの操作を実行する回路を使用することで、 O ( n )個の論理ゲートとO (log n )個の時間ステップを使用する加算器を設計できます。[ 3 ] [ 11 ] [ 12 ]
並列ランダムアクセスマシンの計算モデルでは、プレフィックス和を使用して、同時アクセスを禁止する並列マシン上で、複数のプロセッサが同時に同じメモリセルにアクセスできることを前提とする並列アルゴリズムをシミュレートできます。ソートネットワークを使用すると、一連の並列メモリアクセス要求を、同じセルへのアクセスがシーケンス内で連続するように順序付けできます。次に、スキャン操作を使用して、要求されたセルへの書き込みに成功したアクセスを決定し、メモリ読み出し操作の結果を、同じ結果を要求する複数のプロセッサに分配できます。[ 22 ]
Guy Blellochの博士論文[ 23 ]では、並列プレフィックス操作は、Connection Machineなどのマシンによって提供されるデータ並列モデルの形式化の一部を形成しています。Connection Machine CM-1 および CM-2 は、上記のアルゴリズム 1 を実装できるハイパーキューブネットワークを提供しましたが、CM-5 はアルゴリズム 2 を実装するための専用ネットワークを提供しました。[ 24 ]
グレイコードの構成では、連続するシーケンス値が1ビット位置で互いに異なるという性質を持つバイナリ値のシーケンスにおいて、数値nは、 nとn /2 (nを1ビット右にシフトして形成される数値)の排他的論理和を取るだけで、シーケンスの位置nのグレイコード値に変換できます。逆の操作、つまりグレイコード化された値xをバイナリ数にデコードすることはより複雑ですが、 xのビットのプレフィックス和として表現できます。プレフィックス和内の各加算操作は、2を法として実行されます。この種のプレフィックス和は、現代のコンピュータで利用可能なビット単位のブール演算を使用して、xを2のべき乗の数だけ左にシフトして形成される各数値とxの排他的論理和を計算することで効率的に実行できます。 [ 25 ]
並列プレフィックス(基底となる結合法則として乗算を使用)は、並列多項式補間の高速アルゴリズムを構築するためにも使用できます。特に、補間多項式のニュートン形式の分割差分係数を計算するために使用できます。 [ 26 ]このプレフィックスベースのアプローチは、(合流)エルミート補間の一般化分割差分を取得するため 、およびヴァンデルモンドシステムの並列アルゴリズムに も使用できます。[ 27 ]
並列プレフィックスアルゴリズムは、ベイズフィルタ、カルマンフィルタ、および対応するスムーザーを含む再帰的ベイズ推定法の時間的並列化にも使用できます。 [ 28 ]コアとなるアイデアは、たとえば、ベイズ/カルマンフィルタリング問題の解が、フィルタリング演算子のプレフィックス「和」によってフィルタリング解が得られるように適切に定義された結合フィルタリング演算子で記述されるということです。これにより、並列プレフィックスアルゴリズムを適用してフィルタリングおよびスムーシング解を計算できます。同様のアイデアは、確率的数値計算 のコンテキストで、ある種の確率的微分方程式ソルバーの並列化にも有効です[ 29 ]。
最適制御の文脈では、並列プレフィックスアルゴリズムは、ベルマン方程式およびハミルトン・ヤコビ・ベルマン方程式(HJB方程式)の並列化に使用でき、線形二次レギュレータの特殊なケースも含まれます。[ 30 ] [ 31 ]ここでの考え方は、条件付き値関数の組み合わせ(終点に条件付き)に対する結合演算子を定義でき、この演算子のプレフィックス和がベルマン方程式またはHJB方程式の解を与えるということです。
プレフィックス和は、複数のプロセッサ間で作業を分散するための低コストアルゴリズムとして負荷分散に使用され、その最大の目的は各プロセッサで均等な作業量を達成することです。このアルゴリズムは、各項目に必要な作業量を表す重みの配列を使用します。プレフィックス和が計算された後、作業項目iは、 [ prefixSumValue i / totalWork / numberOfProcessors ]の数のプロセッサユニットに処理のために送信されます。[ 32 ]グラフィカルには、これは各項目の作業量が線分の長さで表され、すべての線分が順番に線上に配置され、結果がプロセッサの数に対応する数のピースに分割される操作に対応します。[ 33 ]
以下は、0から18までの数字について、余りを捨てた四分位数のルックアップテーブルです。これにより、 9×9までの数の乗算が可能になります。
例えば、9に3を掛けたい場合、和と差はそれぞれ12と6であることがわかります。これらの値を表で調べると、36と9が得られ、その差は27で、これは9と3の積です。