最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

parfor ループ内での変数の分類

概要

MATLAB® Coder™ は、parfor ループ内の変数を次の表のいずれかのカテゴリに分類します。分類できない変数はサポートされません。parfor ループに一意に分類できない変数が含まれている場合または変数がそのカテゴリの制限に違反している場合、parfor ループはエラーを生成します。

分類説明
loop (ループ)配列のループ インデックスとして機能します。
sliced (スライス化)そのセグメントがループの異なる反復で演算される配列
broadcast (ブロードキャスト)ループの前に定義される変数。その値はループ内で使用されますが、ループ内で割り当てられることはありません。
reduction (リダクション)ループの反復にわたって値を累積します。反復の順序は考慮されません。
temporary (一時的)ループ内で作成された変数。ただし、スライス化された変数やリダクション変数とは異なり、ループ外では使用できません。

これらの各分類は、次のコード部分では以下のように表示されます。

a=0;
c=pi;
z=0;
r=rand(1,10);
parfor i=1:10
    a=i;				% 'a' is a temporary variable
    z=z+i;			% 'z' is a reduction variable
    b(i)=r(i);		% 'b' is a sliced output variable; 
                  % 'r' a sliced input variable
    if i<=c			% 'c' is a broadcast variable
	        d=2*a;		% 'd' is a temporary variable
    end
end

スライス化された変数

"スライス化された変数" とは、値がセグメント、つまり "スライス" に分割可能な変数のことであり、これらのスライスは異なるスレッド上で個別に演算されます。ループのそれぞれの反復は、配列の個別のスライス上で動作します。

次の例では、A の 1 つのスライスを示しています。スライスは該当する配列の単一の要素で構成されています。

parfor i = 1:length(A)
   B(i) = f(A(i));
end

スライス化された変数の特徴

parfor ループ内の変数は、次の特徴をもつ場合にスライス化されます。

  • 第 1 レベルのインデックス付けのタイプ — インデックス付けの第 1 レベルが小かっこ () である。

  • 固定インデックス リスト — 第 1 レベルの小かっこ内で、所定の変数のすべての出現に対してインデックスのリストが同じである。

  • インデックス付けの形式 — 変数のインデックスのリスト内で、1 つのインデックスのみがループ変数に関与する。

  • 配列の形 — スライス化された変数への割り当て時に、割り当ての右辺が [] または '' ではない (これらの演算子は、要素の削除を意味します)。

第 1 レベルのインデックス付けのタイプ。スライス化される変数では、第 1 レベルのインデックス付けは小かっこ () で囲まれます。たとえば、A(...) です。A.x のようにドット表記を使用して変数を参照する場合、変数はスライス化されません。

左側の変数 A はスライス化されません。右側の変数 A はスライス化されます。

A.q(i,12)                        A(i,12).q

固定インデックス リスト。スライス化される変数のインデックス付けの第 1 レベルの小かっこ内では、指定された変数のすべての出現に対してインデックスのリストは同じです。

左側の変数 Bi および i+1 で別の場所でインデックス化されるため、B はスライス化されません。右側の変数 B はスライス化されます。

parfor i = 1:10
  B(i) = B(i+1) + 1;
end
parfor i = 1:10
  B(i+1) = B(i+1) + 1;
end

インデックス付けの形式。スライス化される変数のインデックスのリスト内では、1 つのインデックスの形式が ii+ki-kk+i または k-i です。

  • i は、ループ変数です。

  • k は、定数または単純な (インデックス付けされていない) 変数です。

  • その他のインデックスは、定数、単純な変数、コロンまたは end です。

配列にインデックスを付けるループ変数を指定してその他の変数を使用する場合、これらの変数はループ内に指定できません。これらの変数は parfor ステートメント全体を実行している間、値が変わりません。ループ変数とそれ自身を組み合わせてインデックス式を形成することはできません。

次の例では、i はループ変数、j および k はインデックス付けされていない変数です。

変数 A はスライス化されない変数 A はスライス化される
A(i+f(k),j,:,3)
A(i,20:30,end)
A(i,:,s.field1)
A(i+k,j,:,3)
A(i,:,end)
A(i,:,k)

配列の形。スライス化された変数は、一定の形を保たなければなりません。次の例では、変数 A はスライス化されません。

A(i,:) = [];
A(end + 1) = i;

ブロードキャスト変数

"ブロードキャスト変数" とは、ループ変数またはスライス化された変数以外の、ループ内で変更されない変数のことです。

リダクション変数

"リダクション変数" は、すべての反復に同時に依存するが反復順序には依存しない値を累積します。

この例は、スカラー リダクション割り当てを使用する parfor ループを示しています。この例では、リダクション変数 x を使用して、ループの 10 回の反復にわたる合計を累積します。スレッド上の反復の実行順は考慮されません。

x = 0;
parfor i = 1:10
   x = x + i;
end
x

expr が MATLAB 式である場合、リダクション変数は代入ステートメントの両辺に配置されます。

X = X + exprX = expr + X
X = X - exprリダクション関数のリダクション割り当て、結合性および可換性を参照してください。
X = X .* exprX = expr .* X
X = X * exprX = expr * X
X = X & exprX = expr & X
X = X | exprX = expr | X
X = min(X, expr)X = min(expr, X)
X = max(X, expr)X = max(expr, X)
X=f(X, expr)
関数 f はユーザー定義関数でなければなりません。
X = f(expr, X)
リダクション関数のリダクション割り当て、結合性および可換性を参照してください。

利用可能な各ステートメントは、"リダクションの割り当て" と呼ばれます。リダクション変数は、このタイプの割り当てのみに配置できます。

次の例は、リダクション変数 X の一般的な使用法を示しています。

X = ...;            % Do some initialization of X
parfor i = 1:n
    X = X + d(i);
end

このループは次と等価です。ここで、各 d(i) は異なる反復により計算されます。

X = X + d(1) + ... + d(n)

ループが標準的な for ループである場合、各反復内の変数 X は、ループに入る前に、またはループの前の反復からその値を取得します。ただし、この概念は parfor ループには適用されません。

parfor ループでは、X の値は各スレッド内で直接的に更新されません。その代わり、d(i) の追加が各スレッド内で行われ、i の範囲は そのスレッドで実行される 1:n のサブセット全体となります。次に、ソフトウェアは結果を X に累積します。

同様にリダクション

r=r<op> x(i)
は、以下と等価です。
r=r<op>x(1)] <op>x(2)...<op>x(n)
演算 <op> が最初に x(1)...x(n) に適用され、次に部分的な結果が r に適用されます。

演算 <op> が 2 つの入力をとる場合、次のいずれかの条件を満たす必要があります。

  • typeof(x(i)) の 2 つの引数をとり、typeof(x(i)) を返す。

  • typeof(r) の 1 つの引数および typeof(x(i)) の 1 つの引数をとり、typeof(r) を返す

リダクション変数のルール

すべてのリダクション割り当てで同じリダクション関数またはリダクション演算を使用する-  リダクション変数に対して、その変数のすべてのリダクション割り当てで同じリダクション関数またはリダクション演算を使用しなければなりません。次の例では、左側の parfor ループはリダクション割り当ての 1 つのインスタンスに + を使用して、別のインスタンスに * を使用しているため、無効となります。

リダクション変数の無効な用法リダクション変数の有効な用法
parfor i = 1:n
  if A > 5*k
    A = A + 1;
  else 
    A = A * 2;
  end
parfor i = 1:n 
  if A > 5*k
    A = A * 3;
  else 
    A = A * 2;
  end

リダクション関数のパラメーターおよび戻り値の型の制限-  リダクション r=r<op> x(i) は、typeof(x(i)) の引数をとり、typeof(x(i)) を返す必要があります。または typeof(r) および typeof(x(i)) の引数をとり、typeof(r) を返す必要があります。

次の例では、無効なループ r は固定小数点型であり、2 はこの型ではありません。これを修正するには、r と同じ型になるように 2 をキャストします。

リダクション変数の無効な用法リダクション変数の有効な用法
function r = fiops(in)
r=fi(in,'WordLength',20,...
  'FractionLength',14,...
  'SumMode','SpecifyPrecision',...
  'SumWordLength',20,...
  'SumFractionLength',14,...
  'ProductMode', 'SpecifyPrecision',...
  'ProductWordLength',20,...
  'ProductFractionLength',14);
parfor i = 1:10
    r = r*2;
end
r=fi(in,'WordLength',20,...
  'FractionLength',14,... 
  'SumMode','SpecifyPrecision',... 
  'SumWordLength',20,...
  'SumFractionLength',14,... 
  'ProductMode','SpecifyPrecision',... 
  'ProductWordLength',20,...
  'ProductFractionLength',14); 
T = r.numerictype; 
F = r.fimath; 
parfor i = 1:10 
    r = r*fi(2,T,F);     
end

次の例では、リダクション関数 fcn は入力 u が固定小数点の場合に処理を行わないため、無効となります(+ および * 演算は自動的にポリモーフィックです)。ポリモーフィック バージョンの fcn を記述して、予想される入力の型を処理しなければなりません。

リダクション変数の無効な用法リダクション変数の有効な用法
function [y0, y1, y2] = pfuserfcn(u)
    y0 = 0;
    y1 = 1;
    [F, N] = fiprops();
    y2 = fi(1,N,F);
    parfor (i=1:numel(u),12)
        y0 = y0 + u(i);
        y1 = y1 * u(i);
        y2 = fcn(y2, u(i));
    end
end
 
function y = fcn(u, v)
  y = u * v;
end
function [y0, y1, y2] = pfuserfcn(u)
    y0 = 0;
    y1 = 1;
    [F, N] = fiprops();
    y2 = fi(1,N,F);
    parfor (i=1:numel(u),12)
        y0 = y0 + u(i);
        y1 = y1 * u(i);
        y2 = fcn(y2, u(i));
    end
end
% fcn handles inputs of type double 
% and fi
function y = fcn(u, v)
    if isa(u,'double')
        y = u * v;
    else
        [F, N] = fiprops();
        y = u * fi(v,N,F);
    end
end

function [F, N] = fiprops()
    N = numerictype(1,96,30);
    F = fimath('ProductMode',...
        'SpecifyPrecision',...
        'ProductWordLength',96);
end

リダクション関数のリダクション割り当て、結合性および可換性

"リダクション割り当て"。MATLAB Coder では、parfor ループ内のリダクション変数の読み込みは、リダクション ステートメント内以外では許可されません。次の例では、リダクション ステートメント r=r+i の後の foo(r) の呼び出しは、ループの無効化の原因となります。

function r = temp %#codegen
  r = 0;
  parfor i=1:10
    r = r + i;
    foo(r);
  end
end

リダクション割り当ての結合性。リダクション変数の定義でユーザー定義の関数 f を使用する場合、parfor ループの確定的な動作を得るには、リダクション関数 f が結合的でなければなりません。

メモ

f が結合的ではない場合、MATLAB Coder はエラーを生成しません。この推奨事項を満たすコードを記述しなければなりません。

結合的にするには、関数 f はすべての ab および c について次を満たさなければなりません。

f(a,f(b,c)) = f(f(a,b),c)

リダクション割り当ての可換性。+.min および max を含む一部の結合的な関数は、可換性も備えています。つまり、これらの関数はすべての a および b について次を満たします。

f(a,b) = f(b,a)

リダクション割り当ての関数 f は可換的でなくてはなりません。f が可換的ではない場合、異なるループの実行により異なる回答が返される可能性があります。

f が既知の非可換的な組み込みでない限り、ソフトウエアはこれを可換性があると仮定します。

一時変数

"一時変数" とは、インデックス付けされていない、直接割り当てられているターゲットであり、リダクション変数ではない変数です。次の parfor ループでは、a および d は一時変数です。

a = 0;
z = 0;
r = rand(1,10);
parfor i = 1:10
   a = i;          % Variable a is temporary
   z = z + i;
   if i <= 5
      d = 2*a;     % Variable d is temporary
   end
end

for ループの動作とは異なり、MATLAB Coderparfor ループの各反復を実行する前に、一時変数があればクリアにするため効率的です。反復は独立していなければならないため、一時変数の値はループの 1 つの反復から別の反復に渡すことはできません。したがって、一時変数は parfor ループの本体内で指定されなければなりません。そのため、一時変数の値は各反復で個別に定義されます。

parfor ステートメントのコンテキスト内の一時変数は、ループ外に存在する同じ名前の変数とは異なります。

初期化されない一時変数

一時変数がクリアされるのは各反復の開始時であるため、MATLAB Coder は、一時変数が反復内に設定される前にループ内の反復がその一時変数を使用する特定の状況を検出できます。この場合、MATLAB Coder は実行時エラーではなく静的エラーを発行します。実行時エラーが発生した場合に実行の続行を許可することにはあまり意味がないためです。たとえば、次のように記述するとします。

  b = true;
  parfor i = 1:n
     if b && some_condition(i)
        do_something(i);
        b = false;
     end
     ...
  end

このループは、通常の for ループとして許容されますが、parfor ループとしては、b はループ内の割り当てのターゲットとして直接的に発生するため、一時変数となります。したがって、この一時変数は各反復の開始時にクリアされるため、if の条件での使用では初期化されません(parforfor に変更すると、b の値はループの連続的な実行を想定し、do_something(i) は、bfalse に設定されるまで、i の低い値に対してのみ実行されるようになります)。