How to propagate (or introspect) nargout? - matlab

Is there a built-in way to automatically propagate the nargout of a calling function to the called function? (Or some for a called function to figure out the nargout of the calling function?)
For example, say that
% foo.m
function [X, Y] = foo()
[X, Y] = bar();
end
and
% bar.m
function [X, Y] = bar()
X = 1;
if upstream_nargout() < 2
Y = 0;
else
Y = big_nasty_time_consuming_monster();
end
end
Of course, one could always define foo like this
% foo.m
function [X, Y] = foo()
if nargout < 2
X = bar();
else
[X, Y] = bar();
end
end
...or define bar with an extra argument to carry the caller's nargout, but I'm wondering if there's a reasonable way to achieve the same effect without resorting to this.

varargout and nargout works as follows:
% foo.m
function varargout = foo()
[varargout{1:nargout}] = bar();
end
% bar.m
function varargout = bar()
varargout{1} = 1;
if nargout > 1,
fprintf('bar: computing second output\n');
varargout{2} = rand(); % OR big_nasty_time_consuming_monster();
end
end
Then:
>> X = foo
X =
1
>> [X,Y] = foo
bar: computing second output
X =
1
Y =
0.5647
NOTE: The version of foo in the question following "Of course, one could always define foo like this" would certainly work, but this alternative allows you to have a single line in foo calling bar, rather than another if/else. That was the point of the question as I read it.

I don't see any reason to propagate the callers nargout, this should match your requirements:
function [X, Y] = foo()
if nargout < 2
X = bar();
else
[X, Y] = bar();
end
end
.
function [X, Y] = bar()
X = 1;
if nargout < 2
Y = 0;
else
Y = big_nasty_time_consuming_monster();
end
end
If you really need the calles nargout use evalin('caller','nargout'), but I would never combine nargin/nargout with evalin('caller', you can easily produce code which is impossible to debug.

Related

Evaluate a vector in a piecewise function

I want to evaluate the vector xdata in a piecewise function like this:
dat=load('k2.txt');
xdata = dat(:,1);
ydata = dat(:,2);
n=length(xdata);
p0=[0.0821 6.6 0.4];
y(p0,xdata)
function y_hat = y(p,t)
P=4.885;
T0 = 134.27426;
omega=2*pi/P;
gamma1=0.3539 ;gamma2=0.2851;
c1=0;c2=gamma1+2*gamma2;c3=0;c4=-gamma2;
c0=1-c1-c2-c3-c4;
z= p(2).*((sin(omega.*(t-T0))).^2+((p(3)/p(2)).*cos(omega.*(t-T0))).^2).^(1/2);
lambda1= 0;
lambda3=p(1).^2;
if ((1-p(1)<z) & (z<1+p(1)))
k1 = acos((1-p(1).^2 + z.^2)./(2*z));
k0 = acos(((p(1)).^2+z.^2-1)./(2.*z.*p(1)));
y_hat = 1-1./pi*(p(1).^2.*k0+k1-sqrt((4*z.^2-(1+z.^2-p(1).^2).^2)/4));
end
if (1+p(1)<=z)
y_hat=1-lambda1;
end
if (z<=1-p(1))
y_hat=1-lambda3;
end
end
The problem is that the code doesn't enter none of the if loops and returns nothing. Maybe the reason is that the function tries to fulfill the conditions for all the vector at once? How should I proceed so that y(p0,xdata) returns something?
By the way, I need this because I have to fit a model to data like this:
[theta] = lsqcurvefit(#y, p0, xdata, ydata);
Your code doesn't work, because when you write something like this:
if [1 3 -1] > 0
%code
end
Then "%code" won't be evaluated because it's checking, if the condition holds for every value in the vector.
Let's say you want to define the Heaviside function and evaluate a vector of it. Then, what you do is using a for loop:
x_vals = [-1 1 5];
heav(x_vals)
function y = heav(x)
y = zeros(size(x));
for i = 1:length(x)
if x(i) >= 0
y(i) = 1;
else
y(i) = 0;
end
end
end

Forwarding varargout in matlab non-verbosely

I have a matlab function like:
function [f, fdx] = twice(x)
f = x * 2;
if nargout > 1
fdx = 2;
end
end
I want to call this function from another function, keeping the optional second-argument semantics. However, this is messy:
function [g, gdx] = twiceplusinverse(x)
% this starts to get messy if the arguments to double are long
if nargout > 1
[f, fdx] = twice(x);
else
f = double(x)
end
g = f + 1/x;
if narargout > 1
gdx = fdx + -1/x^2;
end
end
How can I avoid duplicating every function call that has multiple return values? What's a way to write the following that doesn't violate DRY?
if nargout > 1
[f, fda, fdb, fdc] = longfunction(some_func_producing_a(), b, another_func_for_c());
else
f = longfunction(somefunc_like_above(), b, another_func_for_c());
end
You can use varargout as the output of your function and then use a comma-separated list to assign the outputs of the other function. Since you use 1:nargout as the indices in the comma-separated list, the number of output arguments requested from your function will be passed onto the other function automatically.
function varargout = myfunc(x)
[varargout{1:nargout}] = other_func(x);
end

Matlab optional input and output arguments in a function

I am writing a function and I need some help.
This is my function:
function [varargout] = myfunc(x, y, z, optional)
There are two possible outputs: A and B. By setting the compulsory input variables (x,y,z), you get A. If you also set the optional argument, you should get A and B as well.
So, this is the way I am trying to do it:
if (nargin == 4)
varargout{1} = A;
varargout{2} = B;
else
varargout{1} = A;
end
This is not working... Where am I making the mistake?
Thank you in advance!
I don't see a problem with it. The only problem will come if you attempt:
[a,b] = myfunc(1,2,3)
in which case your function will complain that you're trying to assign to a second variable that hasn't been defined. So you need to have some more input / output checking (e.g. via nargout) and act accordingly. (i.e. either specify a custom error, or return b=[], etc.
PS. I'm assuming your function is defined something like:
function varargout = myfunc(x, y, z, optional)
if (nargin == 4); varargout{1} = 1; varargout{2} = 2;
else varargout{1} = 1;
end
end
You need two outputs with varargout. Try this:
[A,varargout] = myfunc(x, y, z, optional)
and
if (nargin > 3)
varargout{1} = B;
end
There are a couple of issues with this code:
First, you haven't put the keyword "function" before declaring
myfunc.
Second, optional is set as the 4th argument. However, this way you
cannot include more than 4 arguments.
Third, you have to be careful with varargout, since it increases the
number of output argument, but it doesn't change the first one
(which is always equal to one).
I don't know which of the above was your main concern, however, the following code should be working:
function varargout = myfunc2(x, y, z, varargin)
if nargin == 4
varargout{1} = 1; % where A=1 and B = 2
varargout{2} = 2;
else
varargout{1} = 1;
end
end
Please have a look to the attached links for more details about varargin and varargout:
http://uk.mathworks.com/help/matlab/ref/varargin.html
http://uk.mathworks.com/help/matlab/ref/varargout.html
I solved it! I'll post here the solution, it could be useful for others. Thank you all!
function [A, varargout] = myfunc(x, y, z, optional)
A = somefunction(x,y,z)
if nargout == 2 && nargin == 4
i = find(A > optional);
B = somefunction(A,i);
varargout{1} = B;
end
In this way, you have an optional output associated to an optional input variable. It works :)

Use a property of a classdef in another .m file?

Here is my code:
f.m:
classdef f < handle
properties (Access = public)
functionString = '';
x;
end
methods
function obj = f
if nargin == 0
syms s;
obj.x = input('Enter your function: ');
obj.functionString = ilaplace(obj.x);
end
end
function value = subsref(obj, a)
t = a.subs{:};
value = eval(obj.functionString);
end
function display(obj)
end
end
end
test.m:
syms s t;
[n d] = numden(f.x); % Here I want to use x, which is the user input, How can I do such thing?
zeros = solve(n);
poles = solve(d);
disp('The Poles:');
disp(poles);
disp('The Zeros:');
disp(zeros);
disp('The Result:');
disp(z(t));
disp('The Initial Value:');
disp(z(0));
disp('The Final Value:');
disp(z(Inf));
When I type test in the command window, it tells me the following:
>> test
??? The property 'x' in class 'f' must be accessed from a class instance because it
is not a Constant property.
As Alex points out, you need an instance of f to access the member property x, like so:
myf = f();
f.x
You do not need an accessor method to get at x as it is defined as a public property. If you chose to make x private, then you'd need an accessor method something like this:
function x = getX( obj )
x = obj.x;
end

Find the f(any value) e.g f(1) or f(2), of a function that the user enter

The main problem here is to evaluate the user function at some point because we don't know if the user will enter a function in x domain or another domain
I tried this but it doesn't work:
function y = f(~)
y = input('Enter you function: ');
end
and this is what I want:
>>f
Enter you function: a^2+3*a-3
>>f(1)
ans =
1
Another solution is to use function handles:
>> f=#(x) x^2+3*x-3
f =
#(x)x^2+3*x-3
>> f(1)
ans =
1
>> f(2)
ans =
7
This solution almost provides the exact requirements in your question. I'd feel kind of queezy using this though with the EVAL. You'd also want to wrap some error checking into this.
classdef f < handle
properties (Access = private)
functionString = '';
end
methods
function obj = f
if nargin == 0
obj.functionString = input('Enter your function: ', 's');
end
end
function value = subsref(obj, a)
a = a.subs{:};
value = eval(obj.functionString);
end
function display(obj)
end
end
end
You can then use this class like:
>> a = f
Enter your function: a^2+3*a-3
>> a(1)
ans =
1
>> a(2)
ans =
7