精简版:
作为第四个参数传递的函数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)));
注意vals1
是vals0
通过交换元素 2 和 8 获得的。“匿名”函数anon
计算其输入的非无限元素中的最大值。
鉴于这些定义,下面的两个调用
accumarray(idxs, vals0, [], anon)
accumarray(idxs, vals1, [], anon)
仅在它们的第二个参数(vals0
vs )上有所不同,应该产生相同的结果,因为和vals1
之间的差异仅影响对其中一个调用的参数中值的顺序,并且此函数的结果对 的顺序不敏感论据中的元素。vals0
vals1
anon
事实证明,这两个表达式中的第一个可以正常计算并产生正确的结果1:
>> accumarray(idxs, vals0, [], anon)
ans =
6
5
7
然而,第二个失败了:
>> 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
上面最后一次调用的输出可以看出,第二次调用kluge
回调的参数是数组[Int]
。这毫无疑问地告诉我,accumarray
它的行为与记录的3不同(因为idxs
没有指定长度为 1 的数组要传递给accumarray
' 的函数参数)。
事实上,从这个和其他测试中,我确定,与我的预期相反,传递给的函数accumarray
被调用超过max(idxs)
(= 3) 次;在上面涉及的表达式中kluge
,它被称为 5 次。
这里的问题是,如果不能依赖accumarray
's 函数参数的实际调用方式,那么使该函数参数健壮的唯一方法是在其中包含许多额外的代码来执行必要的检查。这几乎肯定会要求函数有多个语句,这排除了匿名函数。(例如,上面的函数kluge
比 更健壮anon
,但我不知道如何适应匿名函数。)不能使用匿名函数accumarray
大大降低了它的效用。
所以我的问题是:
如何指定可以作为健壮参数的匿名函数?
accumarray
1在这篇文章中显示的所有 MATLAB 输出中,我已从 MATLAB 的典型过度填充中删除了空白行。
2我欢迎您提出任何其他故障排除建议;解决这个问题比它应该的要困难得多。
3
特别是,请参阅“函数按如下方式处理输入:”行之后的第 1 到第 5 项。