gop による MPI_Allreduce 機能の実現

この例では、関数 gop およびそれを利用する関数 gplus および gcat について確認します。これらはシンプルな関数に見えますが、実は並列プログラミングにおける極めて強力なツールであることがわかります。

関数 gop を使用すると、すべてのラボで定義される変数の結合二項演算を実行することができます。これによって、すべてのラボの変数の総和を求められるようになるだけでなく、すべてのラボにおける変数の最小値と最大値を求めたり、変数を連結したりするなど、多くの便利な演算を実行できるようになります。

関連ドキュメンテーション:

この例のコードは以下の関数に含まれています。

function paralleltutorial_gop

%#ok<*NOPRT>: disable code analyzer printing warning

はじめに

並列プログラミングを行う場合は、変数がすべてのラボで定義されるようにすることや、変数がすべてのラボに存在するためにその変数に関する演算を実行しなければならなくなることがよくあります。たとえば、以下のように spmd ステートメントを入力して定義するとします。

spmd
    x = labindex
end
Lab  1: 
  
  x =
  
       1
  
Lab  2: 
  
  x =
  
       2
  
Lab  3: 
  
  x =
  
       3
  
Lab  4: 
  
  x =
  
       4
  
Lab  5: 
  
  x =
  
       5
  
Lab  6: 
  
  x =
  
       6
  
Lab  7: 
  
  x =
  
       7
  
Lab  8: 
  
  x =
  
       8
  
Lab  9: 
  
  x =
  
       9
  
Lab 10: 
  
  x =
  
      10
  
Lab 11: 
  
  x =
  
      11
  
Lab 12: 
  
  x =
  
      12
  

これをすべてのラボで定義して、すべてのラボにおける x の値の総和を計算する場合を考えます。これはまさに gplus 演算で実行できます。つまり、すべてのラボの x を合計し、すべてのラボで結果を複製します。

spmd
    s = gplus(x);
end

spmd ステートメント内部で代入されている変数はクライアントで Composite として表されます。結果の値は、cell 配列の場合と同様、Composite にインデックスを付けることによってラボからクライアントに取り込まれます。

s{1} % Display the value of s on lab 1.  All labs store the same value.
ans =

    78

さらに、gopgplus および gcat では、関数の出力先となる単一のラボを指定することができます。その場合、他のラボには空のベクトルが返されます。

spmd
    s = gplus(x, 1);
end
s{1}
ans =

    78

この例では、すべてのラボでの加算と同じような演算のホストを実行する方法を示します。MPI の場合、これらは集合演算と呼ばれ、MPI_SUM、MPI_PROD、MPI_MIN, MPI_MAX などがあります。

例の入力データの作成

すべての例で使用するデータは極めてシンプルです。最初に定義した x より若干複雑な 1 行 2 列のバリアント配列です。

spmd
    x = labindex + (1:2)
end
Lab  1: 
  
  x =
  
       2     3
  
Lab  2: 
  
  x =
  
       3     4
  
Lab  3: 
  
  x =
  
       4     5
  
Lab  4: 
  
  x =
  
       5     6
  
Lab  5: 
  
  x =
  
       6     7
  
Lab  6: 
  
  x =
  
       7     8
  
Lab  7: 
  
  x =
  
       8     9
  
Lab  8: 
  
  x =
  
       9    10
  
Lab  9: 
  
  x =
  
      10    11
  
Lab 10: 
  
  x =
  
      11    12
  
Lab 11: 
  
  x =
  
      12    13
  
Lab 12: 
  
  x =
  
      13    14
  

gplus および gcat の使用

ベクトル x がラボごとに異なる値に初期化されたため、すべてのラボにわたって x の値の要素単位の総和などを求めることができます。また、積、最小値および最大値についてはどうでしょうか。これは当初の見込みどおり、以下のようになります。

spmd
    s = gplus(x);
end
s{1}
ans =

    90   102

これは x の値の要素単位の和を返します。ただし、gplusgop 演算 (グローバル演算) の特殊なケースに過ぎません。関数 gop では、バリアント配列の要素について、すべてのラボにわたる任意の結合演算を実行することができます。結合演算の最も基本的な例は加算です。加算は、以下に示すように、どのようにグループ化されるかに影響されないため結合的な演算となります。

(a + b) + c = a + (b + c)

MATLAB® では、加算を @plus 関数ハンドルによって表すことができます。したがって、gplus(x) は以下のように記述することもできます。

spmd
    s = gop(@plus, x);
end
s{1}
ans =

    90   102

ベクトル x は、関数 gcat を使用することにより、すべてのラボにわたって連結できます。また、連結する次元を選択することもできます。

spmd
    y1 = gcat(x, 1); % Concatenate along rows.
    y2 = gcat(x, 2); % Concatenate along columns.
end
y1{1}
y2{1}
ans =

     2     3
     3     4
     4     5
     5     6
     6     7
     7     8
     8     9
     9    10
    10    11
    11    12
    12    13
    13    14


ans =

  Columns 1 through 13

     2     3     3     4     4     5     5     6     6     7     7     8     8

  Columns 14 through 24

     9     9    10    10    11    11    12    12    13    13    14

その他の要素単位演算での gop の使用

すべてのラボにわたる x の値の要素単位の積は、以下のように簡単に計算することができます。

spmd
    p = gop(@times, x);
end
p{1}
ans =

   1.0e+10 *

    0.6227    4.3589

また、すべてのラボにわたる x の要素単位の最大値も以下のように求めることができます。

spmd
    M = gop(@max, x);
    m = gop(@min, x);
end
M{1}
m{1}
ans =

    13    14


ans =

     2     3

論理演算

MATLAB には他にも組み込みの結合演算があります。AND、OR、XOR の論理演算は、それぞれ関数ハンドル @and@or@xor で表されます。たとえば、以下のような論理配列があるとします。

spmd
    y = (x > 4)
end
Lab  1: 
  
  y =
  
       0     0
  
Lab  2: 
  
  y =
  
       0     0
  
Lab  3: 
  
  y =
  
       0     1
  
Lab  4: 
  
  y =
  
       1     1
  
Lab  5: 
  
  y =
  
       1     1
  
Lab  6: 
  
  y =
  
       1     1
  
Lab  7: 
  
  y =
  
       1     1
  
Lab  8: 
  
  y =
  
       1     1
  
Lab  9: 
  
  y =
  
       1     1
  
Lab 10: 
  
  y =
  
       1     1
  
Lab 11: 
  
  y =
  
       1     1
  
Lab 12: 
  
  y =
  
       1     1
  

この場合、すべてのラボにわたって以下の論理演算を y の要素に対して簡単に実行することができます。

spmd
    yand = gop(@and, y);
    yor = gop(@or, y);
    yxor = gop(@xor, y);
end
yand{1}
yor{1}
yxor{1}
ans =

     0     0


ans =

     1     1


ans =

     1     0

ビット演算

MATLAB に組み込まれている結合演算に関する説明の締めくくりとして、AND、OR、XOR のビット演算について見てみます。これらは、それぞれ関数ハンドル @bitand@bitor@bitxor で表されます。

spmd
    xbitand = gop(@bitand, x);
    xbitor = gop(@bitor, x);
    xbitxor = gop(@bitxor,  x);
end
xbitand{1}
xbitor{1}
xbitxor{1}
ans =

     0     0


ans =

    15    15


ans =

     0    12

最小値と最大値の位置の検出

すべてのラボにわたる x の要素単位の最大値がある位置に対応する labindex を見つけるには、若干のプログラミングが必要です。この処理は、以下のようにわずか数行のコードで実行することができます。

type pctdemo_aux_gop_maxloc
function [val, loc] = pctdemo_aux_gop_maxloc(inval)
%PCTDEMO_AUX_GOP_MAXLOC Find maximum value of a variant and its labindex.
%   [val, loc] = pctdemo_aux_gop_maxloc(inval) returns to val the maximum value
%   of inval across all the labs.  The labindex where this maximum value
%   resides is returned to loc.

%   Copyright 2007 The MathWorks, Inc.

    out = gop(@iMaxLoc, {inval, labindex*ones(size(inval))});
    val = out{1};
    loc = out{2};
end

function out = iMaxLoc(in1, in2)
% Calculate the max values and their locations.  Return them as a cell array.
    in1Largest = (in1{1} >= in2{1});
    maxVal = in1{1};
    maxVal(~in1Largest) = in2{1}(~in1Largest);
    maxLoc = in1{2};
    maxLoc(~in1Largest) = in2{2}(~in1Largest);
    out = {maxVal, maxLoc};
end

また、この関数が実装されている場合は、まるで組み込み関数のように簡単に適用することができます。

spmd
    [maxval, maxloc] = pctdemo_aux_gop_maxloc(x);
end
[maxval{1}, maxloc{1}]
ans =

    13    14    12    12

同様に、すべてのラボにわたる x の要素単位の最小値がある位置に対応する labindex を見つける場合も、数行のコードで済みます。

type pctdemo_aux_gop_minloc
function [val, loc] = pctdemo_aux_gop_minloc(inval)
%PCTDEMO_AUX_GOP_MINLOC Find minimum value of a variant and its labindex.
%   [val, loc] = pctdemo_aux_gop_minloc(inval) returns to val the minimum value
%   of inval across all the labs.  The labindex where this minimum value
%   resides is returned to loc.

%   Copyright 2007 The MathWorks, Inc.

    out = gop(@iMinLoc, {inval, labindex*ones(size(inval))});
    val = out{1};
    loc = out{2};
end

function out = iMinLoc(in1, in2)
% Calculate the min values and their locations.  Return them as a cell array.
    in1Smallest = (in1{1} < in2{1});
    minVal = in1{1};
    minVal(~in1Smallest) = in2{1}(~in1Smallest);
    minLoc = in1{2};
    minLoc(~in1Smallest) = in2{2}(~in1Smallest);
    out = {minVal, minLoc};
end

これで、gop を使用して、簡単に最小値を求めることができます。

spmd
    [minval, minloc] = pctdemo_aux_gop_minloc(x);
end
[minval{1}, minloc{1}]
ans =

     2     3     1     1