短縮版:
の 4 番目の引数として渡された関数は、 の最初の引数をエンコードした仕様と一致しないaccumarray
引数で呼び出されることがあります。accumarray
その結果、 への引数として使用される関数accumarray
は、事実上何が異常な状態であるかをテストする必要があります。
問題は、このような異常な状態を 1 式の無名関数でどのようにテストできるかということです。accumarray
そしてより一般的に:の文書化されていない動作に対して堅牢な無名関数をどのように書くことができますか?
完全版:
以下のコードは、今日の私の勤務時間のほとんどを占めていた問題を大幅に要約したものです。
最初のいくつかの定義:
idxs = [1:3 1:3 1:3]';
vals0 = [1 4 6 3 5 7 6 Inf 2]';
vals1 = [1 Inf 6 3 5 7 6 4 2]';
anon = @(x) max(x(~isinf(x)));
Notevals1
は、要素 2 と 8 を交換することによって取得さvals0
れます。「匿名」関数anon
は、その入力の非無限要素の中で最大値を計算します。
これらの定義を考えると、以下の 2 つの呼び出し
accumarray(idxs, vals0, [], anon)
accumarray(idxs, vals1, [], anon)
2 番目の引数 ( vals0
vs ) のみが異なる場合、とvals1
の違いはへの呼び出しの 1 つに対する引数の値の順序にのみ影響し、この関数の結果はの順序に影響されないため、同じ結果が生成されます。その引数の要素。vals0
vals1
anon
結局のところ、これら 2 つの式の最初の式は正常に評価され、正しい結果1が生成されます。
>> accumarray(idxs, vals0, [], anon)
ans =
6
5
7
ただし、2 つ目は次のように失敗します。
>> accumarray(idxs, vals1, [], anon)
Error using accumarray
The function '@(x)max(x(~isinf(x)))' returned a non-scalar value.
この問題をトラブルシューティングするために、私が思いつくことができたのは、別の関数を作成することだけでした (もちろん、「MATLAB の方法で」独自のファイルに)
function out = kluge(x)
global ncalls;
ncalls = ncalls + 1;
y = ~isinf(x);
if any(y)
out = max(x(y));
else
{ncalls x}
out = NaN;
end
end
...そして以下を実行しました:
>> global ncalls;
>> ncalls = int8(0); accumarray(idxs, vals0, [], @kluge)
ans =
6
5
7
>> ncalls = int8(0); accumarray(idxs, vals1, [], @kluge)
ans =
[2] [Inf]
ans =
6
5
7
上記の最後の呼び出しの出力からわかるaccumarray
ように、コールバックへの 2 番目の呼び出しの引数kluge
は array でした[Int]
。accumarray
これは、文書化されている3のように動作していないことを疑う余地なく教えてくれます(idxs
長さ 1 の配列がaccumarray
の関数引数に渡されないように指定されているため)。
実際、このテストや他のテストから、予想に反して、渡された関数が(= 3) 回accumarray
以上呼び出されていることがわかりました。max(idxs)
上記を含む式では、kluge
5回呼び出されます。
ここでの問題は、 の関数引数が実際に呼び出される方法に依存できない場合accumarray
、この関数引数を堅牢にする唯一の方法は、必要なチェックを実行するために多くの追加コードを含めることです。これにはほぼ確実に、関数に複数のステートメントが必要になるため、無名関数は除外されます。(たとえば、kluge
上記の関数は よりも堅牢ですanon
が、匿名関数に適合する方法がわかりません。) で匿名関数を使用できないとaccumarray
、その有用性が大幅に低下します。
だから私の質問は:
への強力な引数となる無名関数を指定する方法は?
accumarray
1この投稿に示されているすべての MATLAB 出力で、MATLAB の典型的なオーバー パディングから空白行を削除しました。
2その他のトラブルシューティングに関する提案があれば、コメントを歓迎します。この問題のトラブルシューティングは、本来よりもはるかに困難でした。
3特に、 「関数は次のように入力を処理します:」
という行の直後の項目番号 1 から 5 を参照してください。