メッセージ パッシングを使った π の数値推定

この例では spmd ステートメント取り扱いの基本と、それがどのような形で並列計算実行の対話型手段となるのかを示します。これを行うために、π を近似する比較的単純な計算を実行します。

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

関連する例:

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

function paralleldemo_quadpi_mpi

はじめに

ここでは以下の事実を利用します。

左辺の積分を近似することで、π の近似値を求めます。

並列プールで並列計算を実行し、spmd キーワードを使用してコードの並列ブロックをマークします。最初に、現在開いている並列プールのサイズを確認します。

p = gcp;
p.NumWorkers
ans =

    12

計算の並列化

4/(1 + x^2) を 0 から 1 まで数値積分して、π を近似します。

type pctdemo_aux_quadpi.m
function y = pctdemo_aux_quadpi(x)
%PCTDEMO_AUX_QUADPI Return data to approximate pi.
%   Helper function used to approximate pi.  This is the derivative 
%   of 4*atan(x).

%   Copyright 2008 The MathWorks, Inc.
y = 4./(1 + x.^2);

図中に示すような [0, 1] の部分区間に対し関数の積分を各ワーカー (ラボ) に計算させることにより、作業をワーカー間で分割します。

変数 a および b をすべてのワーカーで定義しますが、区間 [a, b] が図に示された部分区間に対応するように、それらの値が labindex に応じて決まるようにします。そのうえで、区間が適正であることを確認します。spmd ステートメント本文のコードは、並列プールのすべてのワーカーで並列に実行されることに注意してください。

spmd
    a = (labindex - 1)/numlabs;
    b = labindex/numlabs;
    fprintf('Subinterval: [%-4g, %-4g]\n', a, b);
end
Lab  1: 
  Subinterval: [0   , 0.0833333]
Lab  2: 
  Subinterval: [0.0833333, 0.166667]
Lab  3: 
  Subinterval: [0.166667, 0.25]
Lab  4: 
  Subinterval: [0.25, 0.333333]
Lab  5: 
  Subinterval: [0.333333, 0.416667]
Lab  6: 
  Subinterval: [0.416667, 0.5 ]
Lab  7: 
  Subinterval: [0.5 , 0.583333]
Lab  8: 
  Subinterval: [0.583333, 0.666667]
Lab  9: 
  Subinterval: [0.666667, 0.75]
Lab 10: 
  Subinterval: [0.75, 0.833333]
Lab 11: 
  Subinterval: [0.833333, 0.916667]
Lab 12: 
  Subinterval: [0.916667, 1   ]

ここで、すべてのワーカーで MATLAB 求積法を使用し、各積分の近似値を求めます。上図に示すように、いずれも同じ関数で演算が行われますが、演算対象は [0, 1] の異なる部分区間となります。

spmd
    myIntegral = integral(@pctdemo_aux_quadpi, a, b);
    fprintf('Subinterval: [%-4g, %-4g]   Integral: %4g\n', ...
            a, b, myIntegral);
end
Lab  1: 
  Subinterval: [0   , 0.0833333]   Integral: 0.332565
Lab  2: 
  Subinterval: [0.0833333, 0.166667]   Integral: 0.32803
Lab  3: 
  Subinterval: [0.166667, 0.25]   Integral: 0.31932
Lab  4: 
  Subinterval: [0.25, 0.333333]   Integral: 0.307088
Lab  5: 
  Subinterval: [0.333333, 0.416667]   Integral: 0.292162
Lab  6: 
  Subinterval: [0.416667, 0.5 ]   Integral: 0.275426
Lab  7: 
  Subinterval: [0.5 , 0.583333]   Integral: 0.257707
Lab  8: 
  Subinterval: [0.583333, 0.666667]   Integral: 0.239713
Lab  9: 
  Subinterval: [0.666667, 0.75]   Integral: 0.221994
Lab 10: 
  Subinterval: [0.75, 0.833333]   Integral: 0.204949
Lab 11: 
  Subinterval: [0.833333, 0.916667]   Integral: 0.188836
Lab 12: 
  Subinterval: [0.916667, 1   ]   Integral: 0.173804

結果の加算

ワーカーで関数の積分の担当部分をすべて計算し終わったら、結果を加算して [0, 1] 全体での積分を求めます。関数 gplus を使用してすべてのワーカーの myIntegral を加算し、すべてのワーカーでの合計を返します。

spmd
    piApprox = gplus(myIntegral);
end

クライアントでの結果の検査

変数 piApprox は spmd ステートメントの内部に割り当てられたため、クライアント上で Composite としてアクセスできます。Composite オブジェクトは、1 つの要素に各ワーカーを対応させた場合の cell 配列に似ています。Composite にインデックスを付けると、対応する値がワーカーからクライアントに戻されます。

approx1 = piApprox{1};   % 1st element holds value on worker 1.
fprintf('pi           : %.18f\n', pi);
fprintf('Approximation: %.18f\n', approx1);
fprintf('Error        : %g\n', abs(pi - approx1))
pi           : 3.141592653589793100
Approximation: 3.141592653589792700
Error        : 4.44089e-16