Nesting multiple functions in Matlab - matlab

I have two nested functions in Matlab. The outer one uses fminunc and I would like your help how to correctly pass through it some arguments. Here my code
clear
rng default
%Some useful parameters
number_starting=10^3;
r=10^5;
J=2;
epsilon_sim=-evrnd(0,1,r,J+1); %rx(J+1)
options = optimoptions(#fminunc, 'MaxFunctionEvaluations', 10^4 ,'MaxIterations', 10^4, 'StepTolerance', 10^(-8), 'Display', 'off');
u_starting=normrnd(0,1,number_starting,J); %rxJ
This is the outer function which uses fminunc
function conv_conjugate=G_star(P, number_starting, options, u_starting,epsilon_sim)
fval=NaN(number_starting,1);
exitflag=NaN(number_starting,1);
for t=1:number_starting
try
coeff=u_starting(t,:).'; %starting values, column vector
[~,fval_temp,exitflag_temp]=fminunc(#obj,coeff, options);
fval(t)=fval_temp;
exitflag(t)=exitflag_temp;
catch
end
end
fval(exitflag>0,:);
conv_conjugate=-min(fval);
end
This is the inner function
function inner=obj(coeff)
comp1=sum(P.*(coeff.'));
comp2=mean(max(epsilon_sim+[coeff.' 0],[],2));
inner=-(comp1-comp2);
end
Here I try, for example, to evaluate the outer function at a given P and it clearly gives me a mistake because some arguments are not correctly passed through obj. Could you advise?
P_0=[0.7387,0.1562];
G_star(P_0, number_starting, options, u_starting,epsilon_sim);

There are two different ways that you can implement this.
1: The simple way
We create an anonymous function that encapsulates function values. Your inner function becomes:
function inner=obj(coeff,P,epsilon_sim)
comp1 = sum(P.*(coeff.'));
comp2 = mean(max(epsilon_sim+[coeff.' 0],[],2));
inner = -(comp1-comp2);
end
such that all values it uses are passed into it as arguments, then we create an anonymous function with one argument that calls obj with all its arguments:
#(x)obj(x,P,epsilon_sim)
This is used as follows:
[~,fval_temp,exitflag_temp] = fminunc(#(x)obj(x,P,epsilon_sim),coeff, options);
2: The more obscure way
I say more obscure because this method makes it harder to see what is happening with variables.
Here we create a nested function, which shares variables with the function it is nested in. A nested function is defined inside another function, and will only be visible to that function:
function conv_conjugate = G_star(P,number_starting,options,u_starting,epsilon_sim)
fval = NaN(number_starting,1);
exitflag = NaN(number_starting,1);
for t = 1:number_starting
coeff = u_starting(t,:).'; %starting values, column vector
[~,fval_temp,exitflag_temp] = fminunc(#obj,coeff, options);
fval(t) = fval_temp;
exitflag(t) = exitflag_temp;
end
fval(exitflag>0,:);
conv_conjugate = -min(fval);
% Nested function:
function inner=obj(coeff)
comp1 = sum(P.*(coeff.'));
comp2 = mean(max(epsilon_sim+[coeff.' 0],[],2));
inner = -(comp1-comp2);
end
end % Note this "end" terminates the enclosing function, and is mandatory.
In the nested function, P and epsilon_sim are shared with the enclosing function.

Related

Axes output not assigned

I'm working on an assignment in which we create a function that creates a blank figure. I think I have most of the function correct, but I also know that parts of it aren't. It is a very simple function, but I'm not sure exactly how to use the outputs. Below are the function and the code calling that function.
function [ax, f] = create_axes(fignum)
figure(fignum)
clf(fignum, 'reset')
ax = axes('Parent',fignum)
axis(ax,'equal')
box(ax,'on')
end
Code to call the above function:
fignum = 317;
[ax,f] = create_axes(fignum)

How to assign each element/column of output to a different variable

In Matlab some functions adapt their output to the number of output variables in the call. For example I can do:
A=[[1 2 3];[4 5 6]];
s=size(A);
And I get
s=[2, 3];
But if I want to handle independently width and height I can do:
[h, w]=size(A);
And I get:
h=2;
w=3;
Now, if I have a function that always output a vector of let's say 3 elements. Is there a way to assign each element to a different variable?
I mean to avoid an scenery like this:
pos=getPosition();
X=pos(1);
Y=pos(2);
Z=pos(3);
I hope I have explained what I mean.
I've had the same problem. Mostly with functions handling coordinates as in your example. My solution was to create the following function:
function varargout = dealOneByOne(vector)
% Assign each column of vector to each variable on the output variables
%
for i=1:size(vector,2)
varargout{i}=vector(:,i);
end
end
Then you can just do
[X,Y,Z]=dealOneByOne(getPosition());
I'm not aware of a simpler way to do it.
Let's define a test function as follows:
function x = test()
x = [1 2 3];
end
Given the function above, this is what I would normally perform in order to split the output array into many distinct variables:
out = num2cell(test());
[a,b,c] = deal(out{:});
A wrapper function can be defined in order to avoid spreading the above assignment into multiple lines:
[a,b,c] = vout_num(test());
function varargout = vout_num(x)
C = num2cell(x);
varargout = C(:).';
end
In your example, the wrapper function would be used as follows:
[X,Y,Z] = vout_num(getPosition());

function handles in Octave

I have a question regarding function(handles) in Octave.
So, I want to call a function, which accepts two variables and returns two(the implementation is faulty; but not relevant in this case).
According to the documentation this should be quite straightforward:
function [ret-list] = name (arg-list)
body
endfunction
I'm trying the following:
function two_d_comp = twodcomp
twodcomp.twoDperp=#perp;
^
end
function twoDperp[vmag, vangle]=perp(x,y)
W = hypot(y,x);
vmag = y/W;
vangle = x/y;
end;
I saved the function in a file called twodcomp.m.
When I call the function as follows:
[X, Y] = twodcomp.twoDperp(1,2)
Octave spits out the following:
error: #perp: no function and no method found
error: called from
twodcomp at line 2 column 20
I managed to remove the error by removing the output arguments vmag and vangle, as follows:
function twoDperp=perp(x,y)
But this is obviously not really what I want.
Do you guys happen to have some pointers as to what I'm doing wrong?
Cheers
Your initial function twodcomp: you cannot have the output variable (before the =) be named the same as your function name (after the =).
Then if you want to assign an anonymous function (MATLAB docs, Octave docs) using the # notation, you can still pass the desired inputs.
So rewrite it like:
% Include empty parentheses after a function name to make it clear which is the output
function output = twodcomp()
% Not sure why you're assigning this function to a struct, but
% still give yourself the ability to pass arguments.
% I'm assuming you want to use the output variable,
% and not reuse the main function name (again)
output.twoDperp = #(x,y) perp(x,y);
end
With your second function, you just need to remove the twoDperp before your output arguments. In your question you state the expected syntax from the docs, but then didn't follow it...
function [vmag, vangle] = perp(x,y)
W = hypot(y,x);
vmag = y/W;
vangle = x/y;
end
Now these can be used like so:
% Deliberately using different variable names to make it clear where things
% overlap from the function output. twodcomp output is some struct.
myStruct = twodcomp();
% The output struct has the field "twoDperp" which is a function with 2 outputs
[m, a] = myStruct.twoDperp(1,2);

Use of varargin in octave

I am trying to use varargin in octave but seems that it is getting some problem. Here is my code:
into2.m
function [result] = into2(x)
result = x*2;
endfunction
into3.m
function [result] = into3(x)
result = x*3;
endfunction
calc.m
function [result1] = calc(varargin, x)
fn1 = varargin{1};
fn2 = varargin{2};
result1 = fn1(x) + fn2(x);
endfunction
test1.m (main function)
function [] = test1()
result= calc(#into2,#into3,2);
disp(result);
endfunction
test1() is main function calling calc() and passing two function handles and one scalar. I expect that varargin should have #into2,#into3 and x should have 2. However, varargin has #into2 and x has #into3. I tried changing order but two functions passed do not go into one argument; each argument has only one function. I believe that varargin should have a cell, but seems not working. I am using Octave 4.2. (Putting MATLAB into tag because the two should be similar.)
The issue is that varargin must appear as the last input argument to a function. If it is not the last, then it is simply treated as an input parameter named varargin instead. From the documentation:
If the special parameter name varargin appears at the end of a function parameter list it indicates that the function takes a variable number of input arguments
So in effect, your calc function is functionally no different from:
function result = calc(y, x)
What you'll want to do instead, is place varargin last in the list of input arguments and modify the logic within calc.
function result = calc(x, varargin)
fn1 = varargin{1};
fn2 = varargin{2};
result = fn1(x) + fn2(x);
end
As a side note, it's not clear why exactly you need to use varargin in this scenario since you don't actually have a variable number of inputs.

MATLAB Return value of first non-empty argument (built-in COALESCE function)

Is there something inbuilt in MATLAB which functions similar to the SQL COALESCE function. I want that function to return the first 'existing' value from all the arguments.
For example,
clear A B; C=10; COALESCE(A,B,C)
should return value of C (because A and B are unassigned/don't exist).
I know it would be very easy to code, and I am just being lazy here. But, I would be surprised if MATLAB doesn't have a similar function.
As far as I know there is no built-in function for that. But you can easily write your own.
Note that it is not possible in Matlab to pass a variable that has not been defined prior of using it. Therefore your proposed call clear A B; C=10; COALESCE(A,B,C) is invalid and will throw an error. Instead we can define an empty variable using var=[].
The following code creates two empty variables A, B and and assigns C=10. Inside the function coalesce we assume at the beginning that all variables are empty. In the for-loop we return the first non-empty variable. In the version without for-loop we get the index of the first non-zero element and then return the corresponding content of the cell if a non-zero element exists.
If you want the function to be accessible from everywhere within Matlab, see the documentation here.
function testcoalesce
A = [];
B = [];
C = 10;
COALESCE(A,B)
COALESCE(A,B,C)
end
% with for-loop (much faster)
function out = COALESCE(varargin)
out = [];
for i = 1:length(varargin)
if ~isempty(varargin{i})
out = varargin{i};
return;
end
end
end
% without for-loop (slower)
function out = COALESCE(varargin)
out = [];
ind = find(cellfun('isempty', varargin)==0, 1);
if ~isempty(ind);
out = varargin{ind};
end
end
The output is as expected:
ans =
[]
ans =
10
Timing the two functions showed, that the first solution using the for-loop is approximately 48% faster than the function without loop.
(10 samples, 1'000'000 iterations, 3 variables & 20 variables)