mcpField
M
matlab-diagnose-parfor

matlab-diagnose-parfor

github.com/matlab開発1.2k58 回インストール1 日前に更新
リポジトリ

matlab-diagnose-parfor について

MATLAB の `parfor` における変数分類の問題を診断し、修正するコーディングスキルです。推測ではなく MATLAB のコードアナライザーを基準とし、分類別の修正例と再検証手順を示します。

主な機能

  1. 01最初にコードアナライザーを実行
  2. 02診断結果から分類原因を特定
  3. 03MATLAB のコード再構成パターンを提示
  4. 04アナライザーで修正を再確認

活用シーン

  1. 01`parfor` の分類エラーの調査
  2. 02`for` ループの `parfor` への書き換え
  3. 03修正した `parfor` コードの検証

MCP 対応

ワークフローでは `mcp__matlab__check_matlab_code` MCP ツールを使い、`parfor` を含む MATLAB コードを解析して検証します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-diagnose-parfor

インストール後、Claude Code で/matlab-diagnose-parforを入力して読み込まれたか確認します。

同梱ファイルmanifest.yamlreferences/parfor-analyser-messages.md

詳細

parfor の変数分類を診断して修正する

parfor の分類ルールを記憶だけで推測しないでください。 LLM の学習データには、これらのルールに関する不完全で、しばしば誤った説明が含まれています。 MATLAB のコードアナライザー(checkcode/codeIssues/mcp__matlab__check_matlab_code)だけが信頼できる情報源です。コードアナライザーは、実行時に使われるものとまったく同じ分類器を実装しています。必ず最初に実行し、決して推測しないでください。

使用する場合

  • ユーザーが問題を報告したり、サポートを求めたりしている、parfor を含むコード全般
  • ユーザーが parfor の分類エラーを受け取った場合(実行時またはエディター内)
  • ユーザーが for ループを parfor に変換したい場合
  • parfor でエラーが発生する理由、実行できない理由、または分類が原因で遅くなる理由をユーザーが尋ねた場合
  • parfor コードへの変更を提案しようとしている場合 — まずコードアナライザーを実行してください

使用しない場合

  • parfor は実行できるものの遅い場合 — パフォーマンスやプールの選択に関する質問であり、分類エラーではありません
  • ワーカーにパス、環境、ツールボックスなどのセットアップや状態が必要な場合 — parfor の変数の問題ではありません
  • コードに parfor が記載されているだけで、ユーザーが問題に言及していない場合

ワークフロー

必ずこの順序で進めてください。分類ルールを推測しないでください。

  1. コードアナライザーを実行します。 mcp__matlab__check_matlab_code MCP ツールを使って、parfor ループを含むファイルを解析します。 Bash 経由で MATLAB をシェルから実行してはいけません — 必ず MCP ツールを使ってください。正確なエラーメッセージを確認します。

  2. エラーの種類を特定します。 メッセージに基づいて判断します(下の表を参照)。

  3. 該当する修正パターンを適用します。(「パターン」セクションを参照)。

  4. 確認します。 修正したコードに対して mcp__matlab__check_matlab_code を再実行し、parfor の分類エラーがゼロであることを確認します。

エラーメッセージと根本原因

48 件すべての parfor アナライザーのメッセージ(ID 付き)の一覧については、 references/parfor-analyser-messages.md を参照してください。以下の表では、 最も一般的な分類エラーを取り上げています。

checkcode メッセージ根本原因修正パターン
"Unable to classify variable 'X'"包括的なエラーで、原因はさまざまです。多くの場合、不正なスライス(添字の不整合、ループ変数を含まないインデックス指定)や、不正なアクセスの組み合わせ(例:インデックス指定されたリダクション)が原因です。構造体フィールドへのアクセスも、このエラーを引き起こす特定の要因の 1 つです。具体的なアクセスパターンを特定し、1 つのカテゴリに収まるように再構成するか、競合する役割を分割します
"multiple sliced accesses...do not all have the same list of subscripts"同じ変数が異なる添字パターンでスライスされています(例:A{i,1}、A{i,2})。単一の代入を使います:A(i,:) = {...}
"Variable 'X' is indexed...but it is not a valid sliced output variable"添字の 1 つが非決定的(ランダム、関数呼び出しなど)であるか、ループ変数が複数の次元に現れるか、または添字パターンがスライスのルールに違反しています。問題のある添字を事前に計算し、ループ変数がちょうど 1 つの次元にだけ使われ、残りの添字が固定されるように再構成します
"accessed with an invalid combination of sliced indexing expressions and non-indexed reads"同じイテレーション内で、変数がスライスによるインデックス指定で書き込まれ、かつ全体が読み取られています。役割が競合しています。2 つの変数に分けます。1 つはスライス書き込み用、もう 1 つは全体読み取り用のスナップショットまたはブロードキャストコピーです
"The temporary variable 'X' might be used after the PARFOR loop" / "Temporary variable 'X' must be set inside the parfor loop before it is used"変数が条件付き(if 分岐内のみ)で代入されるため、MATLAB は一時変数として扱いますが、ループ後に使われるか、経路によっては設定前に読み取られています。スライス出力(イテレーションごとの値を保存)と、ループ後のリダクションに再構成します
"When indexing a sliced variable with a nested for loop variable, the range...must be a row vector of positive constant numbers or variables"内側のループが for j = 1:(expr) であり、expr がリテラル定数でもブロードキャスト変数でもありません。内側のループ範囲を定数またはブロードキャスト変数にするか、ローカルな一時変数に蓄積して、外側のイテレーションごとにスライス変数へ 1 回だけ代入します
"The entire array or structure 'X' is a broadcast variable"変数全体が使われており(ループ変数によるインデックス指定がなく)、読み取り専用です。エラーではなく、パフォーマンスに関する警告です。大きな場合は parallel.pool.Constant(X) を使います

変数の分類ルール(リファレンス)

parfor は各変数を、次のいずれか 1 つのカテゴリに分類します。

カテゴリルール例
Loopループインデックス変数ですparfor i = 1:N
Slicedいずれか 1 つの次元でループ変数によってインデックス指定されます(先頭の次元に限りません)。すべてのアクセスで同じ添字パターンを使います。ループ変数には、リテラル定数またはブロードキャスト変数を加減できます(例:A(i+1,:)、A(:,i-k)。ここで k はブロードキャスト変数です)。A(i,:) = ...、A(:,i) = ...、A(i+1) = ...
Broadcast変数全体が使われ(ループ変数によるインデックス指定がなく)、読み取り専用ですtotal = sum(bigArray)
ReductionX = X op expr または X = expr op X の形式で、X は変数全体を指し、op は +、.*、&、| などの結合則を満たす演算子です。total = total + val
Temporaryイテレーション内で最初に使われるときに代入され、ループ後には使われませんtemp = rand(10)

重要な制約: 変数は、必ずいずれか 1 つのカテゴリにのみ該当する必要があります。用途が混在すると(例:構造体フィールドをリダクションとして使う、または同じ変数を異なる添字でスライスする)、分類に失敗します。

パターン

修正 1:構造体フィールドをスライス出力として使用 → 通常の配列

エラー:「変数 'out' を分類できません」

構造体で「分類できません」が発生する最も一般的な原因です。ユーザーは構造体フィールドにスライスして代入しようとして、out.field(i) = someFcn() と記述しますが、out の第1階層のインデックス指定は括弧ではなくドット(.field)です。スライス変数には、ループ変数を使った第1階層の () または {} によるインデックス指定が必要です。スライスにドットによるインデックス指定を使用することはできません。

% BROKEN: first-level subscript on out is dot, not paren
parfor i = 1:N
    out.x(i) = computeX(i);
    out.y(i) = computeY(i);
end

修正方法: スライス出力には個別の配列を使い、ループの後で構造体にまとめます。

xVals = zeros(1, N);
yVals = zeros(1, N);
parfor i = 1:N
    xVals(i) = computeX(i);
    yVals(i) = computeY(i);
end
out.x = xVals;
out.y = yVals;

関連するパターンとして、構造体フィールドをリダクションとして使う場合があります(results.sum = results.sum + val)。同じルールが適用されます。各フィールドをそれぞれ独立したスカラー変数に取り出し、個別にリダクションしてから、ループの後で構造体にまとめます。

修正 2:複数のスライスされた添字 → 単一の代入

エラー:「複数のスライスアクセス…すべて同じ添字リストではありません」

% BROKEN: {i,1}, {i,2}, {i,3} are three different subscript patterns
output = cell(N, 3);
parfor i = 1:N
    [a, b, c] = computeStuff(i);
    output{i,1} = a;
    output{i,2} = b;
    output{i,3} = c;
end

修正方法: 添字を一貫させ、括弧でインデックス指定する単一の代入を使用します。

output = cell(N, 3);
parfor i = 1:N
    [a, b, c] = computeStuff(i);
    output(i,:) = {a, b, c};
end

注:複数のセルを代入する場合は、{} による波括弧インデックスではなく、セルを代入する () による丸括弧インデックスを使用してください。

修正 3:無効なスライス添字パターン

エラー:「変数 'X' にインデックスが指定されています…しかし、有効なスライス出力変数ではありません」

スライス変数では、ループ変数をちょうど1つの次元のインデックスに使用し、残りの添字は固定する必要があります(リテラル、ブロードキャスト変数、またはコロン)。よくある違反パターンは次の3つです。

parfor i = 1:N
    out(i, randi(5)) = val;      % (a) non-deterministic subscript
    out2(i, 1:4, i) = row;      % (b) loop variable in two dimensions
    for j = 1:(N-1)
        out3(i, j) = fcn(i,j);  % (c) nested-for range is not constant
    end
end

修正方法:

(a) 非決定的なインデックスを parfor の前に事前計算するか、ローカル一時変数に蓄積してから行全体を一度に代入します。

parfor i = 1:N
    localRow = zeros(1, 5);
    localRow(randi(5)) = val;
    out(i,:) = localRow;
end

(b) ループ変数が重複する次元を削除します。i が1つの次元だけをインデックスするように構成を変更します。

parfor i = 1:N
    out2(i,:) = computeRow(i);  % i in dim 1 only
end

(c) ネストした for の範囲を定数またはブロードキャスト変数にするか、ローカル変数に収集してからスライス出力に一度だけ代入します。

innerN = N - 1;  % broadcast (constant before parfor)
parfor i = 1:N
    row = zeros(1, innerN);
    for j = 1:innerN
        row(j) = fcn(i, j);
    end
    out3(i, 1:innerN) = row;
end
修正 4:スライス書き込みと全体読み取りの併用

エラー:「変数 'data' を分類できません」

スライスされた 読み取り とブロードキャスト(全体)読み取りの併用は許可されています。この場合、変数は単にブロードキャストに「変化」します。分類できないのは、同じ反復内で、スライスされた書き込みと同じ変数の全体読み取りを併用する場合です。多くの場合、全体読み取りはスライス出力変数からサイズや型の情報を取り出そうとしているだけです。

% BROKEN: data is sliced-write (data(i,j) = ...) AND read whole (size(data,2))
data = buildMatrix(); % 
parfor i = 1:size(data,1)
    for j = 1:size(data,2) % This counts as a "full read" of data
        data(i,j) = myFunc(i,j);
    end
end

修正方法: 必要な定数情報をループの前に取り出します。

data = buildMatrix();
[N,M] = size(data);
parfor i = 1:N
    for j = 1:M
        data(i,j) = myFunc(i,j);
    end
end

スライス出力変数の「全体読み取り」が、変数内の実際の値に依存する場合、この修正方法は適切ではありません。また、反復が独立していない可能性を示していることがあります。

修正 5:リダクションが標準形式ではない

エラー:「変数 'X' を分類できません」

リダクションは、X が変数全体(インデックス指定なし)であり、op が +、.* などの結合的な演算子である場合に、厳密に次のいずれかの形式である必要があります:X = X op expr、X = expr op X、または X = fcn(X, expr)。fcn には union、max などの任意の結合的な関数を指定できます。

% BROKEN: indexed reduction
counts = zeros(1, 5);
parfor i = 1:100
    bin = randi(5);
    counts(bin) = counts(bin) + 1;  % indexed reduction - not supported
end

修正方法: 反復ごとに蓄積してからリダクションします。

counts = zeros(1, 5);
parfor i = 1:100
    bin = randi(5);
    localCounts = zeros(1, 5);
    localCounts(bin) = 1;
    counts = counts + localCounts;  % whole-variable reduction
end
修正 6:一時変数が誤って警告される

すべての反復で使用前に変数へ値を代入しているにもかかわらず、checkcode が警告する場合は、反復内での最初の参照が(インデックス指定ではなく)全体への代入になっていることを確認してください。

% BROKEN: temp is not fully-assigned as first reference
parfor i = 1:10
    temp.a = rand();
    temp.b = 2*rand();
    result(i) = temp.a * temp.b;
end

修正方法: temp を単一の代入で作成します。

parfor i = 1:N
    temp = struct('a', rand(), 'b', 2*rand()); % Ok - single non-indexed assignment
    result(i) = sum(temp);
end
修正 7:ループ後も保持する必要がある条件付き更新

エラー:「一時変数 'X' は PARFOR ループ後に使用される可能性があります」

一時変数はループの後では使用できません。これは parfor の基本的なルールであり、条件付き代入に特有のものではありません。「これまでの最良値」のパターンが失敗するのは、条件文内の bestscore = score がリダクション形式(X = X op expr)に一致しないため、分類器がリダクションとして扱えないからです。その結果、一時変数として扱われ、ループの終了時に破棄されます。

% BROKEN: bestscore doesn't match reduction form — classified as temporary
bestscore = -Inf;
parfor i = 1:N
    score = expensiveCompute(i);
    if score > bestscore
        bestscore = score;
        X = candidates(i);
    end
end
% bestscore and X are undefined here

修正方法: 候補をすべてスライス出力として計算してから、ループの後でリダクションします。

scores = zeros(1, N);
allX = cell(1, N);
parfor i = 1:N
    scores(i) = expensiveCompute(i);
    allX{i} = candidates(i);
end
[bestscore, idx] = max(scores);
X = allX{idx};

規約

  • 診断の前に必ずコードアナライザーを実行してください。 mcp__matlab__check_matlab_code(MCP ツール)、codeIssues(R2022b 以降)、または checkcode を使用してください。アナライザーはランタイムとまったく同じ分類器を実装しており、信頼できる唯一の情報源です。記憶だけを頼りに診断してはいけません。
  • 修正を必ずアナライザーで検証してください。 修正したファイルに対して、parfor のエラーがなくなるまでアナライザーを再実行してから、解決したと判断してください。1 つの問題を修正すると、ほかの問題が明らかになる場合があります。
  • コードを実行しないでください。 並列プールの起動が遅い、または利用できない場合があります。コードアナライザーは、分類エラーをすべて静的に検出します。
  • セマンティクスを維持してください。 修正後も、元の for ループと同じ結果を生成する必要があります。
  • 変更は最小限にしてください。 分類の問題だけを修正してください。ユーザーから依頼がない限り、アルゴリズム全体を再構成しないでください。

Copyright 2026 The MathWorks, Inc.


コメント