Main Content

スライス化された変数

"スライス化された変数" とは、値がセグメント、つまり "スライス" に分割可能な変数のことであり、これらのスライスは複数のワーカーで個別に演算されます。ループのそれぞれの反復は、配列の個別のスライス上で動作します。スライス化された変数を使用すると、クライアントとワーカー間の通信を削減できます。

この例では、ワーカーは fA の要素に個別に適用します。

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

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

parfor ループ内の変数は、次の特性をすべて備えている場合にスライス化されます。

  • 第 1 レベルのインデックス付けのタイプ - インデックス付けの第 1 レベルが小かっこ () または中かっこ {} である。

  • 固定インデックス リスト — 第 1 レベルの小かっこまたは中かっこ内で、指定された変数の出現箇所すべてについてインデックスのリストが同じである。

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

  • 配列の形状 — 配列は一定の形状を保つ。スライス化された変数に代入するときに、代入式の右辺を [] または '' にすることはできません。これらの演算子が要素を削除しようとするためです。

第 1 レベルのインデックス付けのタイプ。スライス化された変数では、第 1 レベルのインデックス付けは小かっこ () または中かっこ {} で囲まれます。

スライス化されている配列およびスライス化されていない配列に対する第 1 レベルのインデックス付けの形式を次に示します。

スライス化されていないスライス化
A.xA(...)
A.(...)A{...}

第 1 レベルの後、第 2 レベル以降では、任意のタイプの有効な MATLAB® インデックス付けを使用できます。

次の左側の例に示す変数 A はスライス化されていません。これに対し、右側に示す変数 A はスライス化されています。

A.q{i,12}                         A{i,12}.q

固定インデックス リスト。スライス化された変数の第 1 レベルのインデックス付けでは、指定された変数のすべての出現箇所についてインデックスのリストは同じです。

左側の変数 A はスライス化されません。ii+1 により A に異なる場所でインデックスが付けられるためです。右側のコードでは、変数 A が正しくスライス化されます。

スライス化されていないスライス化
parfor i = 1:k
    B(:) = h(A(i), A(i+1));
end
parfor i = 1:k
    B(:) = f(A(i));
    C(:) = g(A{i});
end

右側の例は、同一ループ内で小かっこと中かっこの両方を使用して第 1 レベルのインデックス付けの出現箇所を示していますが、これは許容できます。

次の左側の例は、変数 A のインデックス付けがすべての場所で同じではないため A をスライス化しません。右側の例は、AB の両方をスライス化します。A のインデックス付けは B のインデックス付けと同じではありません。ただし、AB のインデックス付けは、どちらもそれぞれ一貫性があります。

スライス化されていないスライス化
parfor i=1:10
    b = A(1,i) + A(2,i)
end
A = [ 1  2  3  4  5  6  7  8  9  10; 
     10 20 30 40 50 60 70 80 90 100];
B = zeros(1,10);
parfor i=1:10
    for n=1:2
        B(i) = B(i)+A(n,i)
    end
end

インデックス付けの形式。スライス化された変数の第 1 レベルのインデックス付けでは、厳密に 1 つのインデックス式が ii+ki-k または k+i の形式になります。インデックス i はループ変数であり、k はスカラー整数の定数または単純な (インデックスのない) ブロードキャスト変数です。その他のインデックス式は、正の整数の定数、単純な (インデックスのない) ブロードキャスト変数、入れ子にされた for ループのインデックス変数、コロンまたは end です。

i をループ変数とすると、左側に示す変数 A はスライス化されておらず、一方で右側の変数 A はスライス化されています。

スライス化されていないスライス化
A(i+f(k),j,:,3) % f(k) invalid for slicing
A(i,20:30,end)  % 20:30 not scalar
A(i,:,s.field1) % s.field1 not simple broadcast var
A(i+k,j,:,3)
A(i,:,end)
A(i,:,k)

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

配列の形状。スライス化された変数は、一定の形状を保たなければなりません。次に示す変数 A はスライス化されていません。

A(i,:) = [];

A がスライス化されない理由は、スライス化された配列の形状を変更すると、クライアントとワーカー間の通信を管理する前提に違反するためです。

スライス化された入力変数と出力変数

スライス化された変数は入力変数、出力変数、またはその両方となる場合があります。MATLAB はスライス化された入力変数をクライアントからワーカーへ、スライス化された出力変数をワーカーからクライアントへと転送します。変数が入力と出力の両方である場合は、両方向に転送されます。

次の parfor ループでは、A はスライス化された入力変数で、B はスライス化された出力変数です。

A = rand(1,10);
parfor ii = 1:10
    B(ii) = A(ii);
end

ただし、反復ごとに、スライス化された変数要素が使用の前に設定されていると MATLAB が判断した場合、MATLAB は変数をワーカーに転送しません。次の例では、A のすべての要素が使用の前に設定されています。

parfor ii = 1:n
    if someCondition
        A(ii) = 32;
    else
       A(ii) = 17;
    end
    % loop code that uses A(ii)
end

インデックス付き代入により、スライス化された出力変数が動的に増加しつつ、既定値が中間のインデックスに挿入されることがあります。次の例では、既定値 0 が A のいくつかの位置に挿入されていることが分かります。

A = [];
parfor idx = 1:10
    if rand < 0.5
        A(idx) = idx;
    end
end

disp(A);
     0     2     0     4     5     0     0     8     9    10

スライス化された変数が入力として明示的に参照されない場合でも、暗黙的な使用により入力として参照される場合があります。次の例では、A のすべての要素が必ずしも parfor ループ内で設定されているわけではありません。そのため、配列の元の値が受け取られて保持され、ループから返されます。

A = 1:10;
parfor ii = 1:10
    if rand < 0.5
        A(ii) = 0;
    end
end

状況によっては、parfor ループは、スライス化された変数のすべてのセグメントがワーカーで必要となる場合があることを前提としなければなりません。次の例では、スライス化された変数のどの要素が実行前に読み取られるかを判別できないため、parfor は可能性のあるすべてのセグメントを送信します。

A = 1:10;
parfor ii=1:11
    if ii <= randi([10 11])
        A(ii) = A(ii) + 1;
    end
end
このような状況では、コードは、スライス化された変数に配列範囲外でインデックスを付けようとするため、エラーが発生することがあります。

スライス化された変数をもつ入れ子にされた for ループ

入れ子にされた for ループ変数をもつスライス化された変数をインデックス付けする場合、次の要件に注意してください。

  • スライス化された変数は対応する for ループで囲まれていなければならない。

    この例の場合、左側のコードでは、スライス化された変数 A のインデックス付けが、j を定義する入れ子にされた for ループの外で行われているため、このコードは機能しません。

    スライス化されていないスライス化
    A = zeros(10);
    parfor i=1:10
        for j=1:10
        end
        A(i,j)=1;
    end
    A = zeros(10);
    parfor i=1:10
        for j=1:10
            A(i,j) = 1;
        end
    end
  • for ループ変数の範囲は、正の定数または変数の行ベクトルでなければならない。

    この例の場合、左側のコードでは、入れ子にされた for ループの上限が関数の呼び出しにより定義されているため、このコードは機能しません。右側のコードでは、その回避方法として、parfor ループの外で、上限を定数変数で定義しています。

    スライス化されていないスライス化
    A = zeros(10);
    
    parfor i=1:10
        for j=1:size(A,2)
            A(i,j)=1;
        end
    end
    A = zeros(10);
    L = size(A,2);
    parfor=1:10
        for j=1:L
            A(i,j)=1;
        end
    end
  • for ループ変数はその for ステートメント以外の方法で割り当ててはならない。

    この例の場合、左側のコードでは、for ループ変数が for ループの中で再割り当てされているため、このコードは機能しません。右側のコードでは、その回避方法として、i を一時変数 t に割り当てています。

    スライス化されていないスライス化
    A = zeros(10);                          
    parfor i=1:10
        for j=1:10
            if i == j
                j = i;
                A(i,j) = j;
            end
        end
    end
    A = zeros(10);
    parfor i=1:10
        for j=1:10
            if i == j
                t = i;
                A(i,j) = t;
            end
        end
    end

関連するトピック