calling function with multi-variable functions - matlab

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)

Related

Using a function that has another function as parameter:

I want to integrate x^2 from 2 to 4 with the trapezoidal integration method. For this, I defined a function trap that takes 4 arguments:
function y = trap( fn, a, b, h )
n = (b-a)/h;
x = a + [1:n-1]*h;
y = h/2*(feval(fn, a) + feval(fn, b) + 2*sum(feval(fn,x)));
and a function f
function y= f(x)
y=x^2
end
Now, by executing trap(f,2,4,0.1), I get the following error:
Not enough input arguments.
Error in f (line 2)
y=x^2
What is the origin of that error?
You have to call trap using the function handle #f, not f.
trap(#f,2,4,0.1)
function y = trap( fn, a, b, h )
n = (b-a)/h;
x = a + [1:n-1]*h;
y = h/2*(fn(a) + fn(b) + 2*sum(fn(x)));
end
function y= f(x)
y = x.^2;
end
which gives, as expected,
ans =
18.67
Also you needed element-wise multiplication in f(x) to compute y = x.^2.
And feval is not necessary. You can directly call fn(a) to evaluate the function.

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

Replicating Simpson's rule, error with eval

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.

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')

Shortening long expressions

I want to create a function handle to the function:
f = #(x) (x-1)*(x-2)*...*(x-50);
How can I do this in MATLAB without typing all 50 terms?
Here is a vectorized solution:
y = prod((x-[1:50]))
Or if you want an anonymous function:
f = #(x) ( prod((x-[1:50])) )
By the way, it might not be faster than #Chris solution (which is good, and I upvoted it), because of Matlab JIT-Accelerator.
You could wrap it in a function. For example,
function y = myfunc(x, n)
y = 1.;
for i = 1:n
y = y*(x-i);
end
end
The function you defined is basically the product of a sequence, which are trivially written as for loops.
In your case you want to compute this result for 50 terms, so you could just use y = myfunc(x, 50) or, if you want this to be a function handle, you could define
f = #(x) myfunc(x, 50);