功能句柄内部的逻辑短路

时间:2015-03-01 19:06:59

标签: matlab lazy-evaluation anonymous-function logical-operators short-circuiting

我有一个函数句柄,可以在任意大小的2d数组上运行:

R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
                 1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
                 DL1./DL2,[minLim maxLim])) ...
                 ,DL1,DL2) - C1;

这是一个自下而上的细分:

  • fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,[minLim maxLim]) - 此位在[minLim maxLim]区间查找已考虑函数的零,其中fFitObj1fFitObj2是之前可用的函数句柄,{{1 }}是一些已知的常量,并且提供了C1
  • DL1, DL2 - @(DL1,DL2)1/(fzero(...))的包装器,允许从外部提供fzeroDL1
  • DL2 - 另一个包装器,允许arrayfun(@(DL1,DL2)...,DL1,DL2)fzero作为矩阵提供时逐个元素地正确操作。
  • DL1, DL2 - 另一个允许从外部提供R2T = @(DL1,DL2) arrayfun(...) - C1;的包装器。

我的问题是,有时矩阵DL1, DL2可能包含DL1, DL2个值,在这种情况下NaN会返回以下错误:

fzero

这就是为什么我自然会想到可用的operations with short-circuiting,所以我尝试将Error using fzero (line 242) Function values at interval endpoints must be finite and real. 纳入其中,以便any(isnan([DL1,DL2]))如果输入为fzero则不会被评估{1}} - 但无论我尝试什么(例如定制的三元运算符),NaN似乎都会被评估并且代码错误。

期望的结果:我想实现对fzero的延迟评估仅在输入有效时发生(在这种情况下,不是fzero) ,并返回NaN,否则如下面编辑中所示。

相关资源:


编辑:

这是一段代码来说明问题(MATLAB 2014a):

NaN

期望的结果,如果B是:

clear variables; clc;

LIM = [0 5];
fFitObj1 = @(x)x.^2; fFitObj2 = @(x)1;
C1 = 100;

[DL1A,DL2A,DL1B] = deal(ones(2));
DL1B(4) = NaN; DL2B = DL1B;

R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
                 1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
                 DL1./DL2,LIM)) ...
                 ,DL1,DL2) - C1;

R2T(DL1A,DL2A) %//case A, runs fine
%{
// ans =
// 
//   -99   -99
//   -99   -99
%}   
R2T(DL1B,DL2B) %//case B, errors due to NaN
%{
// Error using fzero (line 242)
// Function values at interval endpoints must be finite and real.
// 
// Error in @(DL1,DL2)1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM))
//
//
// Error in @(DL1,DL2)arrayfun(@(DL1,DL2)1/(fzero( .....
%}

1 个答案:

答案 0 :(得分:5)

已经mentioned in the comments:执行此内联是疯狂,您最好使用单独的函数/ .m文件。

将是

  • 更快
  • 更易于阅读
  • 更容易编写
  • 易于调试

例如,您可以采用与此类似的方式执行此操作:

function out = R2TComputation(DL1, DL2, minLim, maxLim, C1)
...%Compute whatever R2T would compute.

要获得与原始匿名函数相同的界面,您只需创建

即可
R2T = @(DL1, DL2) R2TComputation(DL1, DL2, minLim, maxLim, C1)

将在您创建此句柄minLim时捕获maxLimC1R2T的当前值。


另一种选择是使用nested function而不是外部的Loren's blog post。它可以访问父函数的变量,但仍然可以使用ifelse以及您需要的所有其他基本工具。唯一的缺点:它不是要从其他文件中访问。

... % Main function stuff
     function out = R2T(DL1, DL2)
         if ...
            out = ...
         ...
     end
... % Use R2T ...

但是,为了自由自拍,这里是if-else的内嵌版本,我是以lazy evaluation的精神写的,我不推荐使用,因为使用单个表达式而不是相应的if - else语句几乎没有任何好处。

ifelse = @(cond, varargin) varargin{1+~cond}(); %Only for the insane

如果您希望pass an anonymous function执行此操作,则需要{{3}}参数为零,ifelse将对其进行评估(这就是()中的最后两个括号ifelse {1}}适用于:

ifelse(true, 42, @()disp('OMG! WTF! THIS IS CRAZY!!111'))

如果您只是将disp的函数调用作为ifelse的参数而没有@(),则在我们访问ifelse之前将调用该函数。这是因为MATLAB(与大多数其他语言一样)首先计算函数的返回值,然后将其作为参数传递给ifelse

在您的情况下,生成的代码将是:

R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
                 ifelse(~any(isnan([DL1, DL2])), ...
                        @() 1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM)), ...
                        NaN), ...
                 DL1, DL2) - C1;