How do I do successive function application in MATLAB with anonymous functions? Something like the following:
g = #(x) #(y) x+y;
g(1)(2)
However MATLAB gives an error at line 2: ()-indexing must appear last in an index expression.
But the following works:
g = #(x) #(y) x+y;
f = g(1);
f(2)
The script above outputs ans=3.
I am not very familiar with MATLAB but I think the ability to manipulate on the function level makes programming much easier. For example, when I need to compute projections of functions onto some subspace of L^2, the projection operator and normalization etc. all output functions that take additional arguments to evaluate to a numerical answer.
MATLAB doesn't support single expression calls like y = g(1)(2) to function handles returned by functions. You can however work your way around this limitation by using temporary variables:
g1 = g(1);
y = g1(2);
As an alternative you could build your own function to wrap around this functionality.
A recursive approach could be:
function f = fevalIterated(f, varargin)
if ~isempty(varargin)
f = fevalIterated(f(varargin{1}), varargin{2:end});
end
Instead of y = g(1)(2) you would call y = fevalIterated(g, 1, 2).
The iterative approach to do this might be faster:
function f = fevalIterated(f, varargin)
for i = 1:numel(varargin)
f = f(varargin{i});
end
As you were asking about the concept of currying in MATLAB, which is really similar to this:
Un-currying
Un-currying would mean to convert a function #(x) #(y) #(z) x+y+z to a function #(x,y,z) x+y+z. This is a very similar concept and you can thus reuse the functionality of fevalIterated to build a function uncurry that can be used like this:
g = uncurry(#(x) #(y) #(z) x+y+z);
y = g(1,2,3)
The function uncurry would be defined as:
function uncurried = uncurry(f)
uncurried = #(varargin) fevalIterated(f, varargin{:});
Currying
To curry a function #(x,y,z) x+y+z would mean to convert it to #(x) #(y) #(z) x+y+z.
Here is a recursive implementation of curry:
function f = curry(f,N)
if N>1
f = #(first) curry(#(varargin)f(first,varargin{:}), N-1);
end
A (faster) iterative implementation would look like this:
function f = curry(f,N)
for i = 1:N-1
f = #(varargin) #(last) f(varargin{:}, last);
end
You can call both via f = curry(#(x,y,z) x+y+z, 3).
Caveat
Although you can do all this in MATLAB, you might suffer from a noticable performance drop if you overdo the whole function handle calling thingy.
f = #(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15) ...
(x1+x2+x3+x4+x5+x6+x7+x8+x9+x10+x11+x12+x13+x14+x15);
%%// Currying vs Comma separated list expansion
%// Comma separated list expansion
tic;
[C{1:15}] = deal(12345);
f(C{:});
toc;
%// Elapsed time is 0.000146 seconds.
%// Currying
g = curry(f,15);
tic;
for i = 1:15
g = g(12345);
end
toc;
%// Elapsed time is 0.015679 seconds.
Related
Trying to get the integral of some experimentally collected data.
After using the envelope and abs functions I'm using the fit function to get the equation I wish to integrate (unfortunately 'poly' isn't giving a close enough fit to the data):
[yupper,ylower] = envelope(signal,1000,'peak');
dat = abs(yupper);
f = fit(x,dat,'linearinterp');
Then when I try
q = integral(f,3e4,9e4);
I get the error:
Error using integral (line 82) First input argument must be a function
handle.
Error in findenergyfromfitcurve (line 10) q = integral(f,3e4,9e4);
I thought f was a (mathematical) function, don't understand what the error is telling me. When I try using 'poly3' incase it's the linearinterp messing things up I still get that error.
TIA
f is a function but its type is cfit not function handle.
integral() function requires function handle, what you can do
is transform cfit into function handle before taking the
integral
The code is as follows
x = rand(5,1);
dat = rand(5,1);
f = fit(x,dat,'linearinterp');
% Create a new function handle
f = #(x)f(x);
q = integral(f, 3e4,9e4, 'ArrayValued', 1)
2) What does the ... 'Array valued', 1) do as well? It didn't work
till I put that in so it must do something
f is a piecewise function, the following illustration is based on the assumption that f is a 2-piecewise linear function, but it can be used for n-piecewise function as well.
The task for fit() function is finding the parameters :
a
b
c
d
k
In terms of code f looks like
function y = f(x,a,b,c,d,k)
% PIECEWISELINE A line made of two pieces
% that is not continuous.
y = zeros(size(x));
% This example includes a for-loop and if statement
% purely for example purposes.
for i = 1:length(x)
if x(i) < k
y(i) = a.* x(i) + b;
else
y(i) = c.* x(i) + d;
end
end
end
To plot a function handle, just use fplot(f)
Here is the graph for f
To sum up, f probably has more than one expression, that's why I set
'ArrayValued' to true so that integral() function knowns f
has more than one expression, omitting it means f has a single
expression which is not true.
I have 3 equations:
f = (exp(-x.^2)).*(log(x)).^2
g = exp(-x.^2)
h = (log(x)).^2
The interval is:
x = 0.05:10
I am able to correctly plot the equations but when I try to find an integral, it says that there is an error.
The code I used to find an integral is:
integral(f,0,Inf)
integral(g,0,inf)
integral(h,0,10)
The integrals for f and g are from 0 to infinity and the integral for h is from 0 to 10. None of my code to find integrals works.
You need to define f,g,h as functions like shown below. See documentation of integral(), it takes a function as its first argument. Matlab integral documentation
x = 0.05:10
f = #(x) (exp(-x.^2)).*(log(x)).^2
g = #(x) exp(-x.^2)
h = #(x) (log(x)).^2
integral(f,0,Inf) % 1.9475
integral(g,0,inf) % 0.8862
integral(h,0,10) % 26.9673
h = #(x) (log(x)).^2
This syntax is called anonymous functions, basically they are nameless functions. In above case it takes x as input and returns log(x) squared.
From now on h is a function and it can be used like this.
h(1) % will be equal 0
For more on anonymous functions refer to matlab anonymous functions guide:
Anonymous Functions
I'm trying to automatically create a function handle that is a sum of function handles. When I tried to do this manually, it worked:
f1 = #(x) x(1);
f2 = #(x) x(2);
f3 = #(x) x(3);
f = #(x) f1(x)+f2(x)+f3(x);
But when I tried to do this automatically (using a for-loop):
aux = {f1,f2,f3};
f = #(x) 0;
for i=1:3
f = #(x) f(x) + cell2mat(aux(i));
end
I get the following error:
Undefined operator '+' for input arguments of type 'function_handle'.
My goal is to use this function handle with fmincon function.
So an alternative solution would also help.
In the first case you are adding the result of the function calls, which works fine. In the second case you are trying to add function handles, which isn't implemented.
The work around would be to use cellfun to evaluate your functions then add the results together:
f = #(x)sum(cellfun(#(c)feval(c,x),aux));
The above assumes that your functions all return a scalar numeric. If that's not the case in your real application then you'll need to modify the use of cellfun appropriately.
I am trying to integrate a function F which is defined as:
function F
x = -3:0.1:3;
F = zeros(1, length(x));
for i = 1:length(x)
if (1.4<= x(i)) && (x(i) <= 1.6)
F(i) = x(i).^2;
else
F(i) = 2;
end
end
end
but the integral function gives me an error saying that there are too many arguments. I think the problem that the function is defined as a points?
The problem with your function, is that integral has no way to pass the arguments you supply to your function F. The function doesn't know that it can just pull certain elements from the vector you created. If you rewrite your function such that for an input (or x value), the output of F is returned, then integral will work as you need given two values to integrate between.
I don't know how to calculate the integral of the sum of function handles in a cell. Please see the below examples:
f{1} = #(x) x;
f{2} = #(x) x^2;
g = #(x) sum(cellfun(#(y) y(x), f));
integral(#(x) exp(g), -3,3);
Error: Input function must return 'double' or 'single' values. Found 'function_handle'.
PS: please don't change the formula, because this is just an example. My real problem is far more complicated than this. It has log and exp of this sum (integral(log(sum), -inf, inf)). So I can't break them up to do the integral individually and sum the integrals.I need to use sum(cellfun). Thank you.
Version: Matlab R2012a
Can anyone help me? Really appreciate.
You cannot add function handles, so anything that tries f{1}+f{2}+... would give an error.
But you can compute the integral of the sums like this, evaluating the function values one at a time and adding up the results:
function cellsum
f{1} = #(x) x;
f{2} = #(x) x.^2;
integral(#(x)addfcn(f,x), -3, 3)
end
function s = addfcn(f,x)
s = zeros(size(x));
for k = 1:length(f)
s = s + f{k}(x);
end
end
Note that x will usually be a vector when the integral command calls your functions with it. So your function definitions should be vectorized, .i.e., x.^2 instead of x^2, etc.