I have a function handle that operates on 2d arrays of arbitrary size:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,[minLim maxLim])) ...
,DL1,DL2) - C1;
Here's a bottom-up breakdown of what it does:
fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,[minLim maxLim])
- This bit looks for a zero of the considered function on the interval [minLim maxLim]
, where fFitObj1
and fFitObj2
are function handles available from before, C1
is some known constant and DL1, DL2
are provided.@(DL1,DL2)1/(fzero(...))
- a wrapper for fzero
that allows DL1
and DL2
to be provided from outside.arrayfun(@(DL1,DL2)...,DL1,DL2)
- another wrapper which allows fzero
to correctly operate element-by-element when DL1, DL2
are provided as a matrix.R2T = @(DL1,DL2) arrayfun(...) - C1;
- yet another wrapper that allows to provide DL1, DL2
from outside.My problem is that sometimes the matrices DL1, DL2
may contain NaN
values, in which case fzero
returns the following error:
Error using fzero (line 242)
Function values at interval endpoints must be finite and real.
This is why I naturally thought of the available operations with short-circuiting, so I tried to incorporate a any(isnan([DL1,DL2]))
into this so that fzero
won't even be evaluated if its inputs would be NaN
- but whatever I try (e.g. a custom-made ternary operator) the fzero
seems to be evaluated and the code errors.
The desired result: I'd like to implement a lazy evaluation of the fzero
to only occur when the inputs are valid (in this case, not NaN
), and return NaN
otherwise as demonstrated in the Edit below.
Related resources:
Here's a piece of code that illustrates the problem (MATLAB 2014a):
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( .....
%}
The desired result, in case B is:
ans =
-99 -99
-99 NaN
As already mentioned in the comments: Doing this inline is madness and you are much better off using a separate function / .m
file.
It will be
You could do this for example in a similar way to this:
function out = R2TComputation(DL1, DL2, minLim, maxLim, C1)
...%Compute whatever R2T would compute.
To get the same interface as your original anonymous function has, you can simply create
R2T = @(DL1, DL2) R2TComputation(DL1, DL2, minLim, maxLim, C1)
which will capture the current values of minLim
, maxLim
and C1
at the time you create this handle R2T
.
Yet another option would be to use a nested function instead of the external one. It would have access to the parent function's variables, yet still be able to use if
, else
and all the other basic tools you need. Only downside: It is not meant to be accessed from within other files.
... % Main function stuff
function out = R2T(DL1, DL2)
if ...
out = ...
...
end
... % Use R2T ...
However, for the sake of freedom of shooting oneself in the foot, here is an inline version of if-else
, which I wrote in the spirit of Loren's blog post and I do not recommend using, as there are hardly any benefits of using a single expression instead of the corresponding if
-else
statements.
ifelse = @(cond, varargin) varargin{1+~cond}(); %Only for the insane
If you want it to do lazy evaluation, you need to pass an anonymous function with zero parameters, which ifelse
will then evaluate (That's what the last two parentheses ()
in ifelse
are for):
ifelse(true, 42, @()disp('OMG! WTF! THIS IS CRAZY!!111'))
If you simply wrote the function call to disp
as an argument to ifelse
without @()
, the function would be called before we even access ifelse
. This is because MATLAB (as most other languages) first computes the return value of the function, which is then passed to ifelse
as a parameter.
In your case the resulting code would be:
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With