Trapezodial Rule Matlab - matlab

I am completing an assignment for a class. We were to follow a flow chart to find the values for the trap rule code. I believe the problem is with my main code.
I am not sure if there is a problem with my function code or my main code, any help would be appreciated.
when I run the section, it display the function as the answer
The following is my mainscript code:
f = #(x) (4*sin (x)) / (exp(2*x)) ;
trap_haskell(f , 0 , 3 , 7)
The rest is my trapezoidal rule code
function [f] = trap_haskell(f, a, b, n)
x = a ;
h = (b - a) / n ;
s = f (a) ;
for k=1:1:n-1
x = x + h ;
s = s + 2 * f(x) ;
end
s = s + f(b) ;
I = (b - a) * s / (2 * n) ;
end

You're returning f as the output argument of trap_haskell which is the input function into trap_haskell itself. The variable I in your code actually stores the integral so it's simply a matter of changing the output variable of the function definition to return the integral instead:
%// ------ Change here
%// |
%// V
function [I] = trap_haskell(f, a, b, n)

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.

Function and its gradient in Matlab

I am working on a Matlab project and I want to make the gradient of the following function in Matlab:
f(x) = c^T * x - sum (log(bi - (ai ^ T) * x)).
Where ai^T are the rows of a random A matrix nxm , where n=2, and m=20
c is random matrix nx1, and x is also random nx1.
b is random matrix mx1.
I've done the following but the results i get don't seem to be right..
function gc0 = gc(x, c, b, A)
for k = 1 : length(A(:,1))
f1(k) = sum(log(b - A(k,:)'*x(k)));
end
gradient(-f1)
gc0 = c - gradient(f1)';
Any ideas? I'd appreciate your help, I'm newbie in Matlab..
It seems that your loop contains a mistake. Looking at the formula above,
I think that the function evaluation should be
f1 = c'*x;
for k = 1 : length(A(1,:))
f1 = f1 - log(b(k) - A(:,k)'*x)
end
A shorter and faster notation for this in Matlab is
f = c'*x - sum(log(b - A' * x)) ;
The function 'gradient' does not calculate the gradient that I think you
want: it returns the differences of matrix entries, and your function f
is a scalar.
Instead, I suggest calculating the derivatives symbolically:
Gradf = c' + sum( A'./(b - A' * x) );

Simplifying function by removing a loop

What would be the best way to simplify a function by getting rid of a loop?
function Q = gs(f, a, b)
X(4) = sqrt((3+2*sqrt(6/5))/7);
X(3) = sqrt((3-2*sqrt(6/5))/7);
X(2) = -sqrt((3-2*sqrt(6/5))/7);
X(1) = -sqrt((3+2*sqrt(6/5))/7);
W(4) = (18-sqrt(30))/36;
W(3) = (18+sqrt(30))/36;
W(2) = (18+sqrt(30))/36;
W(1) = (18-sqrt(30))/36;
Q = 0;
for i = 1:4
W(i) = (W(i)*(b-a))/2;
X(i) = ((b-a)*X(i)+(b+a))/2;
Q = Q + W(i) * f(X(i));
end
end
Is there any way to use any vector-like solution instead of a for loop?
sum is your best friend here. Also, declaring some constants and creating vectors is useful:
function Q = gs(f, a, b)
c = sqrt((3+2*sqrt(6/5))/7);
d = sqrt((3-2*sqrt(6/5))/7);
e = (18-sqrt(30))/36;
g = (18+sqrt(30))/36;
X = [-c -d d c];
W = [e g g e];
W = ((b - a) / 2) * W;
X = ((b - a)*X + (b + a)) / 2;
Q = sum(W .* f(X));
end
Note that MATLAB loves to handle element-wise operations, so the key is to replace the for loop at the end with scaling all of the elements in W and X with those scaling factors seen in your loop. In addition, using the element-wise multiplication (.*) is key. This of course assumes that f can handle things in an element-wise fashion. If it doesn't, then there's no way to avoid the for loop.
I would highly recommend you consult the MATLAB tutorial on element-wise operations before you venture onwards on your MATLAB journey: https://www.mathworks.com/help/matlab/matlab_prog/array-vs-matrix-operations.html

Not enough input arguments error in matlab

This is my matlab code , I got Not enough input argument error in line 2 and i don't know how to fix it. Anyhelp ? Thanks in advance .
function [] = Integr1( F,a,b )
i = ((b - a)/500);
x = a;k = 0; n = 0;
while x <= b
F1 = F(x);
x = x + i;
F2 = F(x);
m = ((F1+F2)*i)/2;
k = k +m;
end
k
x = a; e = 0; o = 0;
while x <= (b - 2*i)
x = x + i;
e = e + F(x);
x = x + i;
o = o + F(x);
end
n = (i/3)*(F(a) + F(b) + 2*o + 4*e)
This code performs integration by the trapezoidal rule. The last line of code gave it away. Please do not just push the Play button in your MATLAB editor. Don't even think about it, and ignore that it's there. Instead, go into your Command Prompt, and you need to define the inputs that go into this function. These inputs are:
F: A function you want to integrate:
a: The starting x point
b: The ending x point
BTW, your function will not do anything once you run it. You probably want to return the integral result, and so you need to modify the first line of your code to this:
function n = Integr1( F,a,b )
The last line of code assigns n to be the area under the curve, and that's what you want to return.
Now, let's define your parameters. A simple example for F is a linear function... something like:
F = #(x) 2*x + 3;
This defines a function y = 2*x + 3. Next define the starting and ending points:
a = 1; b = 4;
I made them 1 and 4 respectively. Now you can call the code:
out = Integr1(F, a, b);
out should contain the integral of y = 2*x + 3 from x = 1 to x = 4.

Matlab - define a general variable

I want to calculate Fourier series for some function func.
I build this method:
function y = CalcFourier(accurate, func, a, b, val_x)
f = #(x) eval(func);
% calculate coefficients
a0 = (2 / (b - a)) * calcArea(func, a , b);
an = (2 / (b - a)) * calcArea(strcat(func, '*cos(2*n*pi*x / (b - a))'), a , b);
an = (2 / (b - a)) * calcArea(strcat(func, '*sin(2*n*pi*x / (b - a))'), a , b);
partial = 0;
an_f = #(n) an;
bn_f = #(n) bn;
for n = 1:accurate
partial = partial + an_f(n)* cos(2*n*pi*val_x / (b - a)) + bn_f(n) * sin(2*n*pi*val_x / (b - a));
end
y = (a0 / 2) + partial;
end
And this - to approximate the coefficient's:
function area = calcArea(func, a, b)
f = #(x) eval(func);
area = (a - b) * (f(a) - f(b)) / 2;
end
On line an = (2 / (b - a)) * calcArea(strcat(func, '*cos(2*n*pi*x / (b - a))'), a , b); I'm getting error:
??? Error using ==> eval
Undefined function or variable 'n'.
Error in ==> calcArea>#(x)eval(func) at 2
f = #(x) eval(func);
Error in ==> calcArea at 3
area = (a - b) * (f(a) - f(b)) / 2;
Error in ==> CalcFourier at 5
an = (2 / (b - a)) * calcArea(strcat(func,
'*cos(2*n*pi*x / (b - a))'), a , b);
>>
Is there any option to declate n as "some constant"? Thanks!
You try to use a variable called n in line 4 of your code. However at that time n is not defined yet, that only happens in the for loop. (Tip: Use dbstop if error at all times, that way you can spot the problem more easily).
Though I don't fully grasp what you are doing I believe you need something like this:
n=1 at the start of your CalcFourier function. Of course you can also choose to input n as a variable, or to move the corresponding line to a place where n is actually defined.
Furthermore you seem to use n in calcArea, but you don't try to pass it to the function at all.
All of this would be easier to find if you avoided the use of eval, perhaps you can try creating the function without it, and then matlab will more easily guide you to the problems in your code.
if the symbolic toolbox is available it can be used to declare symbolic variables , which can be treated as 'some variable' and substituted with a value later.
however a few changes should be made for it to be implemented, generally converting anonymous functions to symbolic functions and any function of n to symbolic functions. And finally the answer produced will need to be converted from a symbolic value to some more easy to handle value e.g. double
quickly implementing this to your code as follows;
function y = test(accurate, func, a, b, val_x)
syms n x % declare symbolic variables
%f = symfun(eval(func),x); commented out as not used
The two lines above show the declaration of symbolic variables and the syntax for creating a symbolic function
% calculate coefficients
a0 = symfun((2 / (b - a)) * calcArea(func, a , b),x);
an = symfun((2 / (b - a)) * calcArea(strcat(func, '*cos(2*n*pi*x / (b - a))'),...
... a , b),[x n]);
bn = symfun((2 / (b - a)) * calcArea(strcat(func, '*sin(2*n*pi*x / (b - a))'),...
... a , b),[x n]);
partial = 0;
the function definitions in in your code are combined into the lines above, note they functions are of x and n, the substitution of x_val is done later here...
for n = 1:accurate
partial = partial + an(val_x,n)* cos(2*n*pi*val_x / (b - a)) +...
... bn(val_x,n) * sin(2*n*pi*val_x / (b - a));
end
The for loop which now replaces the symbolic n with values and calls the symbolic functions with x_val and each n value
y = (a0 / 2) + partial;
y = double(y);
end
Finally the solution is calculated and then converted to double;
Disclaimer: I have not checked if this code generates the correct solution, however I hope it gives you enough information to understand what has been changed and why to carry out the process given in your code above, using the symbolic toolbox to address the issue...