Replicating Simpson's rule, error with eval - matlab

I'm trying to replicate the Simpson's rule by writing a function for it. However, I'm still not clear how I could possibly use eval to transform a string to a actual function in MatLab.
The function is:
function result = simpson(fun, x0, xn, n)
f = eval(fun);
h = (xn-x0)/2;
xstart = f(x0) + f(xn);
x1 = 0;
x2 = 0;
for i = 1:n-1
x = x0 + h*i;
if (mod(i,2) == 0)
x2 = x2 + f(x);
else
x1 = x1 + f(x);
end
end
result = h*(xstart + 2*x2 + 4*x1)/3;
The error reported is
Error using eval
Undefined function or variable 'x'
How could I pass x to a string form of a function?

The clean way to do that: Use a function handle, avoid eval.
Function handles are documented here: http://www.mathworks.de/de/help/matlab/ref/function_handle.html
Define them like this:
sqr = #(x) x.^2;
and then call your function:
simpson(sqr, 1, 2, 3);
within your function, you should e able to call fun(3) and get 9 as a result.
If you have to use eval, I could see two solutions:
The Sneaky way: simpson('#(x) x.^2') (eval creates a proper function handle)
The dirty way:
function result = simpson(fun)
x = 4;
f = eval(fun);
result = f;
return;
end
Call it like this: simpson('x.^2')

The problem here is the way eval is being used. The documentation indicates that in your example the output f would not be a function handle (as is expected by the way the code uses it), but rather the output of the fun function.
So, in order to make the eval function work you need to provide it with it's input.
For example:
fun = 'x.^2';
x = 4;
f = eval(fun);
Results in f == 16
In short, any time you wish to call fun you would have to set x to the appropriate value, call eval and store the result.
For example, in your code:
f = eval(fun);
h = (xn-x0)/2;
xstart = f(x0) + f(xn);
Would become:
h = (xn-x0)/2;
x = x0;
fx0 = eval(fun);
x = xn;
fxn = eval(fun);
xstart = fx0 + fxn;
I would suggest function handles as a safer and easier way of implementing this, but as mentioned in the comments this is not allowed in your case.

Related

How do I call a function handle with an vector rather than a list of arguments?

I was wondering how to call a function handle with an vector of inputs - rather than the list of aguments.
So if I have a function handle which is defined: (I guess it will be clear that I am working on fitting functions here)
fitFunctionHandle = #(a1, wG1, x1,a2, wG2, x2, c, x)(FitGaussianFn(x, [a1, 0, wG1, x1]) +FitGaussianFn(x, [a2, 0, wG2, x2]) + c
And I have an vector of inputs to hand to it
a1Init = 1
wG1Init = 2
x1Init = 3
a2Init = 4
wG2Init = 5
x2Init = 6
a2Init = 7
x = 8
%startPoint = [a1Init, wG1, x1,a2, wG2, x2, c]
inputArray = [a1Init, wG1, x1,a2, wG2, x2, c, x]
How do I call it with the vector startPoint as the input. If I try (for example)
>> fitFunctionHandle(inputArray)
I get an error:
Not enough input arguments.
That makes sense since it is expecting 8 inputs rather than a 8 element vector - but I'm wondering whether there is a way of calling it like that. I think for example in python you can convert an array to a list or something.
I'm aware that I could simplify things in this example case where I have a list of known inputs so I could just do:
fitFunctionHandle(a1Init, wG1, x1,a2, wG2, x2, c, x)
or
fitFunctionHandle(inputArray(1),inputArray(2),inputArray(3,inputArray(4), inputArray(5), inputArray(6),inputArray(7),inputArray(8))
BUT! I guess I'm trying to allow for expansion where I don't know how many arguments there would be.
For bonus points (again since I'm working on fitting functions) - It would be cool to know how to call it when x is a vector as well. I suspect that I would be doing something like
arrayfunc(fitFunctionHandle([startPoint,x]), xVector)
Thanks in advance for your help.
If I understand correctly, you are looking for a way to pass a variable number of input arguments to an anonymous function.
Take a look at this example:
anonymousFunction = #(varargin)(image(varargin{:}));
x = [5 8];
y = [3 6];
C = [0 2 4 6; 8 10 12 14; 16 18 20 22];
input = {C};
anonymousFunction(input{:});
input = {x,y,C};
anonymousFunction(input{:});
You can see in the example that a variable number of inputs is used for calling the anonymous function. Of course, this depends on the actual function that is using the arguments (in this case, image)
Regarding the varargin, the general idea was already presented in UnbearableLightness' answer. I just wanted to address your specific case.
It seems, you want to have some dynamic linear combinations of your FitGaussianFn calls with varying parameters, resulting in some complex function handle. For variable amount of terms, I would recommend to write a separate function to generate the final function handle. I made up a small toy example.
That's my fitFunctionHandle.m function:
function h = fitFunctionHandle(varargin)
n = numel(varargin);
if (n < 2)
error('Not enough input arguments.');
end
% Last input argument is considered t
t = varargin{end};
h = #(x) 0;
for iArg = 1:n-1
a = varargin{iArg}(1);
b = varargin{iArg}(2);
h = #(x) h(x) + (a*sin(b*x+t));
end
end
Each input argument consists of two parameters, that form a sin term. An additional shift parameter t is always passed at last.
And, here's some test script:
% Set up parameters
a1 = 1; b1 = 1;
a2 = 2; b2 = 2;
a3 = 3; b3 = 3;
t = pi/16;
% Evaluation point
x = pi/4;
% Compare results with explicit function calls
h = fitFunctionHandle([a1, b1], t);
res = h(x)
cmp = sin(x+t)
h = fitFunctionHandle([a1, b1], [a2, b2], t);
res = h(x)
cmp = sin(x+t) + 2*sin(2*x+t)
h = fitFunctionHandle([a1, b1], [a2, b2], [a3, b3], t);
res = h(x)
cmp = sin(x+t) + 2*sin(2*x+t) + 3*sin(3*x+t)
You see, it doesn't matter, how many parameter vectors are passed.
The output reveals, that the passed function handles are correct:
res = 0.83147
cmp = 0.83147
res = 2.7930
cmp = 2.7930
res = 4.4598
cmp = 4.4598
Regarding your last question, let's see this test:
% Set up array of t parameters, and get set of function handles
t = [pi/16, pi/8, pi/4];
hh = arrayfun(#(x) fitFunctionHandle([a1, b1], x), t, 'UniformOutput', false);
% Compare results with explicit function calls
for iH = 1:numel(hh)
h = hh{iH};
res = h(x)
cmp = sin(x + t(iH))
end
Here, the t, which is used for all sin terms in fitFunctionHanle, is a vector. The arrayfun call will return a cell array of function handles. Again, the output shows comparable results:
res = 0.83147
cmp = 0.83147
res = 0.92388
cmp = 0.92388
res = 1
cmp = 1
Hope that helps!

I want to feed in a function handle into a matlab function I made

I am trying to feed a function handle into the function I created below. I'm not exactly sure how to do this.
For example, how do I get:
conjugate_gradient(#(y) ABC(y), column_vector, initial_guess)
to not error?
If I use matlab's pcg function in the same way it will work:
pcg(#(y) ABC(y),b,tol).
I tried reading the pcg function, and they do take about this in the function description, however I'm still super inexperienced with MATLAB and had shall we say some difficulty understanding what they did.Thank You!
function [x] = conjugate_gradient(matrix, column_vector, initial_guess)
y = [];
col_size = length(column_vector);
temp = size(matrix);
mat_row_len = temp(2);
% algorithm:
r_cur = column_vector - matrix * initial_guess;
p = r_cur;
k = 0;
x_approx = initial_guess;
for i=1:mat_row_len
alpha = ( r_cur.' * r_cur ) / (p.' *(matrix* p));
x_approx = x_approx + alpha * p;
r_next = r_cur - alpha*(matrix * p);
fprintf(num2str(r_next'*r_next), num2str(i))
y = [y; i, r_next'*r_next];
%exit condition
if sqrt(r_next'*r_next) < 1e-2
y
break;
end
beta = (r_next.'* r_next )/(r_cur.' * (r_cur) );
p = r_next + beta * p;
k = k+1;
r_cur = r_next;
end
y
[x] = x_approx;
end
When you do
f = #(y) ABC(y)
You create a function handle. (Note that in this case it's the same as f=#ABC). This handle is a variable, and this can be passed to a function, but is otherwise the same as the function. Thus:
f(1)
is the same as calling
ABC(1)
You pass this handle to a function as the first argument, which you have called matrix. This seems misleading, as the variable matrix will now be a function handle, not a matrix. Inside your function you can do matrix(y) and evaluate the function for y.
However, reading your function, it seems that you treat the matrix input as an actual matrix. This is why you get errors. You cannot multiply it by a vector and expect a result!

calling function with multi-variable functions

I have the following function which finds the zero of a function using Newton-Raphson:
function [ x,i ] = nr_function( x0,f,fp )
N = 15;
eps = 1e-5;
x=x0;
for i=0:N
if( abs(f(x))<eps )
return;
end
x=x-f(x)/fp(x);
end
I can call the function like this:
f = #(x) x.^3-1
fp = #(x) 3*x.^2
nr_function(3, f,fp)
However, say I instead define my function like this, i.e. taking 2 variables:
f = #(x, q) q*x.^3-1
fp = #(x, q) q*3*x.^2
Then how would I be able to call nr_function with f and fp? I tried nr_function(3, f,fp), but that doesn't work
If q is defined when you call nr_function, you can use an anonymous function in the call. When you do this, then the argument you pass is a new function-handle with variable x and constant q.
f = #(x, q) q*x.^3-1
fp = #(x, q) q*3*x.^2
q = 1;
nr_function(3, #(x)f(x,q), #(x)fp(x,q))
Note: It's not necessary that you use the variable x in the anonymous function. The only importance is to have a single argument in the end. So we can use for example y as the intermediate variable like this:
nr_function(3, #(y)f(y,q), #(y)fp(y,q))
If we expand it to multiple lines, it would look like this:
f = #(x, q) q*x.^3-1
fp = #(x, q) q*3*x.^2
q = 1;
f2 = #(y) f(y,q)
fp2 = #(y) fp(y,q)
nr_function(3, f2, fp2)

Matlab: Create function with another function as argument

I need to create a function f with another function, g, as argument (g is defined in a .m file, not inline). In the body of f, I need to use feval to evaluate g on multiple values; something like:
function y = f(a,b,c,g)
z=feval(g,a,b,c);
y=...
end
What is the syntax ? I tried to use handles, but I got error messages.
You can do it this way:
Define f in an m-file:
function y = f(a,b,c,g)
y = feval(g,a,b,c);
end
Define g in an m-file:
function r = g(a,b,c)
r = a+b*c;
end
Call f with a handle to g:
>> f(1,2,3,#g)
ans =
7
If you do not want to change the body of add, then you could do that:
function s = add_two(a)
s = a + 2;
end
function s = add_three(a)
s = a + 3;
end
function s = add(a, fhandle1, fhandle2)
s = feval(fhandle1, a);
s = s + feval(fhandle2, s);
end
a = 10;
fhandle1 = #add_two; // function handler
fhandle2 = #add_three;
a = add(a, fhandle1, fhandle2);
a

Using inline function with constant arguments in MATLAB

This is a part of my code.
clear all;
clc;
p = 50;
t = [-6 : 0.01 : 6];
f = inline('(t+2).*sin(t)', 't')
v = inline('3*f(p*t+2)','t','f','p')
plot(t,f(t));
v(t,f,p);
figure;
plot(t,v(t,f,p));
Here I have two questions.
Why I have to pass p into the function v even though p is a constant which has already declared ?
How I can get an expression for v completely in terms of t as 3*[(50*t+2)*sin(50*t+2)] or in its simplified form ?
Update
This is an update for the second question
Let
f(x) = 1 + x - x^2
g(x) = sin(x)
If I give f(g(x)), I wanna get the output in words, like this
f(g(x)) = (cos(X))^2 + sin(x)
not in numerical value. Is there any function capable to do that?
1) Why do I have to pass p to v even though p is a constant which has already been declared?
Well, a MATLAB's inline function object has an eval wrapper, so the only variables in its scope are those which were automatically captured from the expression or explicitly specified.
In other words, if you want v to recognize p, you have no other option but declaring it when creating the inline object and passing it to v explicitly. The same goes for f as well!
2) How I can get an expression for v completely in terms of t as 3*[(50*t+2)*sin(50*t+2)] or in its simplified form?
Use anonymous functions, like Shai suggested. They are more powerful, more elegant and much faster. For instance:
v = #(t)(3*(50*t+2)*sin(50*t+2))
Note that if you use a name, which is already in use by a variable, as an argument, the anonymous function will treat it as an argument first. It does see other variables in the scope, so doing something like g = #(x)(x + p) is also possible.
EDIT #1:
Here's another example, this time a function of a function:
x = 1:5;
f = #(x)(x .^ 3); %// Here x is a local variable, not as defined above
g = #(x)(x + 2); %// Here x is also a local variable
result = f(g(x));
or alternatively define yet another function that implements that:
h = #(x)f(g(x)); %// Same result as h = #(x)((x + 2) .^ 3)
result = h(x);
The output should be the same.
EDIT #2:
If you want to make an anonymous function out of the expression string, concatenate the '#(x)' (or the correct anonymous header, as you see fit) to the beginning and apply eval, for example:
expr = '(x + 2) .^ 3';
f = eval(['#(x)', expr]) %// Same result as f = #(x)((x + 2) .^ 3)
Note that you can also do char(f) to convert it back into a string, but you'll have to manually get rid of the '#(...)' part.
EDIT #3:
If you're looking for a different solution, you can explore the Symbolic Toolbox. For example, try:
syms x
f(x) = x + 2
g(x) = x ^ 3
or can also use sym, like so:
f(x) = sym('x + 2');
g(x) = sym('x ^ 3');
Use subs to substitute values and evaluate the symbolic expression.
How about using anonymous functions:
p = 50;
t = -6:0.01:6;
f = #(x) (x+2).*sin(x);
v = #(x) 3*f(p*x+2);
figure;
subplot(1,2,1); plot( t, f(t) ); title('f(t)');
subplot(1,2,2); plot( t, v(t) ); title('v(t)');
Is this what you wanted?
Adding a constant into an inline can be done during its definition.
Instead of
p = 50;
v = inline('3*f(p*t+2)','t','f','p')
You can write
p = 50;
v = inline( sprintf('3*f(%f*t+2)', p), 't','f')