I'm using two distinct functions on matlab: function1 and function2 (each written in a different script).
In the script of function1, I have something like:
function result = function1(y,z)
result = function2(#(x)do_this(x,y,z), #(f)do_that(f,y,z))
function f = do_this(x,y,z)
f = operationOn(x,y,z)
end
function d = do_that(f,x,z)
d = operationOn(f,y,z)
end
end
and in function2's script, I have:
function otherResult = function2(do_this, do_that)
m = matrix;
p = do_this(m)
otherResult = do_that(p)
end
I found that I have a problem in function2, since whenever I try to display p (the result of the function do_this defined in the script1), the value I get is NaN.
I can't see where is the problem? Am I using function handlers in an incorrect way?
Thanks for your help
Related
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.
I just started with MATLAB and I'm seeking advice for how to make a function work with more arguments.
I've built this formula:
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C)))) + ...
exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
Therefore I needed the values for U0, vw, vt, L, R
If I put this in the command window:
D = (1/L*C)-((R^.2)/(4*L^.2));
sD = sqrt(D);
vt = linspace(tmin,tmax,200);
vw = omega;
[vw,vt] = meshgrid(vw,vt);
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C)))) + exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
surf(vw,vt,I)
It works fine.
So, now I want to create a function which reads the values and calculates all the stuff above and returns a surf plot.
My try:
function [u] = test(L,C,R,tmin,tmax,omega,U0)
D = (1/L*C)-((R^.2)/(4*L^.2));
sD = sqrt(D);
vt = linspace(tmin,tmax,200);
vw = omega;
[vw,vt] = meshgrid(vw,vt);
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C))))+exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
surf(vw,vt,I)
end
This error occurs:
Error using alphaToo many output arguments.
Do you have an idea how to make this function work?
What is alpha? It's likely that it exists in your workspace, so when you call those lines from your workspace everything is fine. However, within the test function MATLAB has no visibility of the "base" workspace, and alpha doesn't exist! Pass it as an argument or define it like your other values. Ditto with beta.
Also you have defined the output argument u in your function
% Ouput vvv
function [u] = test(L,C,R,tmin,tmax,omega,U0)
But you never assigned anything to the variable u during the function". If you want to return the surf figure object, assign that to u when it is called.
% Square brackets not needed as only returning one variable
function u = test(L,C,R,tmin,tmax,omega,U0)
% ... stuff
u = surf(vw,vt,I)
end
I'm trying to use arrayfun() to map a function over a cell array. The following is happening:
>> arrayfun(solveFunc, equArray)
Error using arrayfun
First input must be a function handle.
Error in solve>genGuess (line 33)
funcVals = abs(arrayfun(inFunc, xValues));
Error in solve (line 8)
x = genGuess(inFunc, varargin{1}, varargin{2});
Error in makeSolveFunc>#(func)solve(func,start,stop) (line 3)
sFunc = #(func) solve(func, start, stop);
But, the first input IS a function handle. Also... if I manually apply the function to each element of the provided cell array, everything works fine:
>> solveFunc(equArray{1})
ans =
4.7335
>> solveFunc(equArray{2})
ans =
4.7356
Does anyone know why this would be happening? I assumed that if I could manually apply the function to each element of my array, and the return type of the function was consistent and one of the allowed types (you can't for example have arrayfun return an array of function handles... I already tried doing that), it should work. Perhaps that is not the only requirement.
Here is some code that generates this error:
solve.m
function solution = solve(inFunc, start, stop)
%SOLVE solve an equation using Newton's Method
x = genGuess(inFunc, start, stop);
for i = 1:100
m = getSlope(inFunc, x);
x = (m*x - inFunc(x))/m;
end
solution = x;
end
function slope = getSlope(inFunc, x)
%SLOPE calculate the slope at a given point
inc = 1e-5;
if x ~= 0
inc = inc * x;
end
slope = (inFunc(x + inc) - inFunc(x - inc))/(2*inc);
end
function guess = genGuess(inFunc, start, stop)
%GENGUESS get an initial guess to the solution
xValues = linspace(start, stop, 101);
funcVals = abs(arrayfun(inFunc, xValues));
[~, minIndex] = min(funcVals);
guess = xValues(minIndex);
end
charEqu.m
function equ = charEqu(a)
%CHAREQU create a KP model characteristic equation with provided p
equ = #(x) x + a;
end
makeSolveFunc.m
function sFunc = makeSolveFunc(start, stop)
%MAKESOLVEFUNC return a function that solves an equation
sFunc = #(func) solve(func, start, stop);
end
test.m
pArray = 1:5;
equArray = cell(1,arrayLen);
for i = 1:5
equArray{i} = charEqu(pArray(i));
end
solveFunc = makeSolveFunc(1.1*pi, 2*pi);
alphaAArray = arrayfun(solveFunc, equArray);
I have narrowed down the error to something in genGuess(). For some reason, in the line funcVals = abs(arrayfun(inFunc, xValues)); the variable inFunc is a 1x1 cell array containing a function handle. I have no idea why that would be the case. I traced this back to the anonymous function call #(func) solve(func, start, stop); in the makeSolveFunc() function. There it is still a 1x1 cell array containing a function handle. I'm not really sure where that cell array is coming from as that function is getting called from arrayfun().
Background information on what I'm trying to do in case someone wants to suggest a better way:
I'm trying to solve equations using Newton's method. I have written a function that can solve an equation given an initial guess range. This function is the solve() function you can see in the first error message. It takes a function, and the guess range and returns a function that I'm calling solveFunc(). solveFunc() takes a function and solves it using the initial guess range previously provided.
Maybe I'm just too used to functional programming and should just use a loop.
If the arguments passed to the function handle are contents of elements of a cell array, you need to use cellfun instead of arrayfun:
cellfun(solveFunc, equArray)
This is equivalent to
for i=1:length(equArray)
out(i) = solveFunc(equArray{i});
end
since solveFunc is already a function handle.
Check where the error comes from. This line causes the error:
funcVals = abs(arrayfun(inFunc, xValues));
The first input argument is a 1x1 cell containing one function handle. This is caused because equArray is a cell, thus use cellfun as Jonas already mentioned:
pArray = 1:5;
equArray = cell(1,arrayLen);
for i = 1:5
equArray{i} = charEqu(pArray(i));
end
solveFunc = makeSolveFunc(1.1*pi, 2*pi);
alphaAArray = cellfun(solveFunc, equArray);
I've got the function
function [imag2] = sumIntegral(x,w,a,b,c,p)
imag2 = zeros(p-1,p);
for k = 1:p-1
f = #(t)(1:p-1==k)*Integrand[1](t,x,w,a,b,c);
imag2(k,:) = quadv(f,x(k),x(k+1));
end
whereas
Integrand[1] should be real2 of this function
[real2,real3,imag2,imag3] = Integrand(t,x,w,a,b,c,p);
The problem is, if I define the Integrand function before, I get an error, as t is undefined. Do you know how to write real2 as a function in t?
Simply define your quick function out of the for loop
function [imag2] = sumIntegral(x,w,a,b,c,p)
imag2 = zeros(p-1,p);
f = #(t)(1:p-1==k)*Integrand[1](t,x,w,a,b,c);
for k = 1:p-1
imag2(k,:) = quadv(f,x(k),x(k+1));
end
end
You could just make a dummy proxy function that only outputs the first argument:
function real2 = MyIntergrand(t,x,w,a,b,c)
real2 = Integrand(t,x,w,a,b,c);
end
Say that I have a function foo defined as
[a b] = foo(c ).
If I consider a function handle
f = #(c)foo(c)
to be used e.g. in a cellfun call, what I get is an f behaving equivalently to a foo defined like
a = foo(c)
i.e., the returned value b gets lost.
Therefore, when such an f is put in a cellfun call, the output cell will have just the as and will miss the bs (which I currently care about). Visually
cellfun(f,input)
[a(input{1})] ?
[a(input{2})] ?
.... b gets killed along the way
Question: how to define a function handle to foo which catches just the bs? i.e. giving a behavior analogous to a definition of foo like
b = foo(c)
i.e.^2, wasting the as.
Moreover, is it possible to (efficiently) catch both a and b in a unique cellfun call?
From the documentation of cellfun:
[A1,...,Am] = cellfun(func,C1,...,Cn) calls the function specified by function handle func and passes elements from cell arrays C1,...,Cn, where n is the number of inputs to function func. Output arrays A1,...,Am, where m is the number of outputs from function func, contain the combined outputs from the function calls.
So yes, cellfun can use a multi-output function and in this case it simply returns a number of outputs. If you want to use the second one only, you can use ~ to ignore the first one. The same goes for multiple outputs of anonymous functions - they will be returned if you specify multiple output arguments. Here is a simple code:
function test
x{1} = 1;
x{2} = 2;
[~, B] = cellfun(#foo, x);
f=#(c)foo(c);
[A, B] = f(1);
function [a b] = foo(x)
a = x+1;
b = x+2;
end
end
This can be done by using a cell array as the single output of the function, instead of a function with multiple outputs.
Define your function to return a cell array (or create an auxiliary function that calls the original multiple-output function):
function F = foo2(x)
[a,b,c] = foo(x);
F = {a, b, c};
end
And then you can create a handle that calls your function and gets only one of the cells from the cell array.
f = #(x) cell(foo2(x)){2} % This selects the second output
g = #(x) cell(foo2(x)){3} % This selects the third output
Which is almost exactly what you were asking for.
You could even create a handle that returns the n-th output
f = #(x,n) cell(foo2(x)){n}