Composite trapezoid rule not running in Octave - octave

I have the following code in Octave for implementing the composite trapezoid rule and for some reason the function only stalls whenever I execute it in Octave on f = #(x) x^2, a = 0, b = 4, TOL = 10^-6. Whenever I call trapezoid(f, a, b, TOL), nothing happens and I have to exit the Terminal in order to do anything else in Octave. Here is the code:
% INPUTS
%
% f : a function
% a : starting point
% b : endpoint
% TOL : tolerance
function root = trapezoid(f, a, b, TOL)
disp('test');
max_iterations = 10000;
disp(max_iterations);
count = 1;
disp(count);
initial = (b-a)*(f(b) + f(a))/2;
while count < max_iterations
disp(initial);
trap_0 = initial;
trap_1 = 0;
trap_1_midpoints = a:(0.5^count):b;
for i = 1:(length(trap_1_midpoints)-1)
trap_1 = trap_1 + (trap_1_midpoints(i+1) - trap_1_midpoints(i))*(f(trap_1_midpoints(i+1) + f(trap_1_midpoints(i))))/2;
endfor
if abs(trap_0 - trap_1) < TOL
root = trap_1;
return;
endif
intial = trap_1;
count = count + 1;
disp(count);
endwhile
disp(['Process ended after ' num2str(max_iterations), ' iterations.']);

I have tried your function in Matlab.
Your code is not stalling. It is rather that the size of trap_1_midpoints increases exponentionaly. With that the computation time of trap_1 increases also exponentionaly. This is what you experience as stalling.
I also found a possible bug in your code. I guess the line after the if clause should be initial = trap_1. Check the missing 'i'.
With that, your code still takes forever, but if you increase the tolerance (e.g. to a value of 1) your code return.
You could try to vectorize the for loop for speed up.
Edit: I think inside your for loop, a ) is missing after f(trap_1_midpoints(i+1).

After count=52 or so, the arithmetic sequence trap_1_midpoints is no longer representable in any meaningful fashion in floating point numbers. After count=1075 or similar, the step size is no longer representable as a positive floating point double number. That all is to say, the bound max_iterations = 10000 is ludicrous. As explained below, all computations after count=20 are meaningless.
The theoretical error for stepsize h is O(T·h^2). There is a numerical error accumulation in the summation of O(T/h) numbers that is of that size, i.e., O(mu/h) with mu=1ulp=2^(-52). Which in total means that the lowest error of the numerical integration can be expected around h=mu^(1/3), for double numbers thus h=1e-5 or in the algorithm count=17. This may vary with interval length and how smooth or wavy the function is.
One can expect the behavior that the error divides by four while halving the step size only for step sizes above this boundary 1e-5. This also means that abs(trap_0 - trap_1) is a reliable measure for the error of trap_0 (and abs(trap_0 - trap_1)/3 for trap_1) only inside this range of step sizes.
The error bound TOL=1e-6 should be met for about h=1e-3, which corresponds to count=10. If the recursion does not stop for count = 14 (which should give an error smaller than 1e-8) then the method is not accurately implemented.

Related

How to calculate values using for-end and if-else in Octave?

I need to calculate variable Nfj in the following equation:
ea_M = (sf/E)*(2*Nfj)^b + ef*(2*Nfj)^c
so that it is equal to 4 different values of ea: 5.0900e-04, 4.3626e-04, 3.6358e-04, and 2.9084e-04. The results should be 4 values of Nfj which should be stored in results. I am rounding because I think that it is not possible to calculated exactly equal values of ea, without rounding the equality would always be false.
I wrote for it this code, but it does not work as expected: the script runs for a very long time without any results. How can I fix it to work correctly?
sf = 882.07;
ef = 0.59;
b = -0.102969;
c = -0.58;
E = 210000;
ea = [5.0900e-04; 4.3626e-04; 3.6358e-04; 2.9084e-04]
for pos = 1:length(ea)
for Nfj = 1e3:10:1e12
ea_M = (sf/E)*(2*Nfj)^b + ef*(2*Nfj)^c;
if round(ea_M * 10^5)/10^5 == round(ea(pos) * 10^5)/10^5;
disp(ea_M)
disp(Nfj)
results(pos) = Nfj;
end
end
end
You are trying every 10th value, from 103 to 1012: there are 1011 values here to try! This is of course a lot. You will be searching for ever, and you might skip the actual value that would make the equality true.
If you are not able to solve the equation manually, you can use a numerical solver. Let's first print the function:
sf = 882.07;
ef = 0.59;
b = -0.102969;
c = -0.58;
E = 210000;
ea_M = #(Nfj) (sf/E)*(2*Nfj).^b + ef*(2*Nfj).^c;
Nfj = logspace(3,12,1000);
plot(Nfj, ea_M(Nfj))
set(gca, 'xscale', 'log')
It looks like this function is nicely monotonic, and the four values you are looking for are in the interval of 103 to 1012 you were searching. To find where it equals one of your values, we can subtract that value and find where it equals zero. You can very quickly narrow down your search if you start at a point where the function is larger than zero, and one where it is smaller than zero. You halve the interval every time, keeping the half of the interval that contains the zero crossing. The fzero function does just this.
ea = [5.0900e-04; 4.3626e-04; 3.6358e-04; 2.9084e-04];
results = zeros(size(ea));
for pos = 1:numel(ea)
results(pos) = fzero(#(Nfj) ea_M(Nfj) - ea(pos), [1e3,1e12]);
end
results
In MATLAB, this code runs in a small fraction of a second and outputs:
results =
1.0e+10 *
0.0429
0.1849
1.0627
9.1919
and ea_M(results) - ea is approximately zero.
A few notes on the code I posted here:
ea_M is defined as an anonymous function. This makes it easier to reuse the expression, rather than writing it over and over again. I replaced ^ with .^ to allow this function to do the computation on an array of Nfj values at once, rather than only single values. This is necessary for the fzero call.
I plotted the function on a logarithmic scale, because this function calls for that. The same is not true for all functions.
I preallocated the results array, you should avoid increasing the size of an array in a loop.

How to compute Fourier coefficients with MATLAB

I'm trying to compute the Fourier coefficients for a waveform using MATLAB. The coefficients can be computed using the following formulas:
T is chosen to be 1 which gives omega = 2pi.
However I'm having issues performing the integrals. The functions are are triangle wave (Which can be generated using sawtooth(t,0.5) if I'm not mistaking) as well as a square wave.
I've tried with the following code (For the triangle wave):
function [ a0,am,bm ] = test( numTerms )
b_m = zeros(1,numTerms);
w=2*pi;
for i = 1:numTerms
f1 = #(t) sawtooth(t,0.5).*cos(i*w*t);
f2 = #(t) sawtooth(t,0.5).*sin(i*w*t);
am(i) = 2*quad(f1,0,1);
bm(i) = 2*quad(f2,0,1);
end
end
However it's not getting anywhere near the values I need. The b_m coefficients are given for a
triangle wave and are supposed to be 1/m^2 and -1/m^2 when m is odd alternating beginning with the positive term.
The major issue for me is that I don't quite understand how integrals work in MATLAB and I'm not sure whether or not the approach I've chosen works.
Edit:
To clairify, this is the form that I'm looking to write the function on when the coefficients have been determined:
Here's an attempt using fft:
function [ a0,am,bm ] = test( numTerms )
T=2*pi;
w=1;
t = [0:0.1:2];
f = fft(sawtooth(t,0.5));
am = real(f);
bm = imag(f);
func = num2str(f(1));
for i = 1:numTerms
func = strcat(func,'+',num2str(am(i)),'*cos(',num2str(i*w),'*t)','+',num2str(bm(i)),'*sin(',num2str(i*w),'*t)');
end
y = inline(func);
plot(t,y(t));
end
Looks to me that your problem is what sawtooth returns the mathworks documentation says that:
sawtooth(t,width) generates a modified triangle wave where width, a scalar parameter between 0 and 1, determines the point between 0 and 2π at which the maximum occurs. The function increases from -1 to 1 on the interval 0 to 2πwidth, then decreases linearly from 1 to -1 on the interval 2πwidth to 2π. Thus a parameter of 0.5 specifies a standard triangle wave, symmetric about time instant π with peak-to-peak amplitude of 1. sawtooth(t,1) is equivalent to sawtooth(t).
So I'm guessing that's part of your problem.
After you responded I looked into it some more. Looks to me like it's the quad function; not very accurate! I recast the problem like this:
function [ a0,am,bm ] = sotest( t, numTerms )
bm = zeros(1,numTerms);
am = zeros(1,numTerms);
% 2L = 1
L = 0.5;
for ii = 1:numTerms
am(ii) = (1/L)*quadl(#(x) aCos(x,ii,L),0,2*L);
bm(ii) = (1/L)*quadl(#(x) aSin(x,ii,L),0,2*L);
end
ii = 0;
a0 = (1/L)*trapz( t, t.*cos((ii*pi*t)/L) );
% now let's test it
y = ones(size(t))*(a0/2);
for ii=1:numTerms
y = y + am(ii)*cos(ii*2*pi*t);
y = y + bm(ii)*sin(ii*2*pi*t);
end
figure; plot( t, y);
end
function a = aCos(t,n,L)
a = t.*cos((n*pi*t)/L);
end
function b = aSin(t,n,L)
b = t.*sin((n*pi*t)/L);
end
And then I called it like:
[ a0,am,bm ] = sotest( t, 100 );
and I got:
Sweetness!!!
All I really changed was from quad to quadl. I figured that out by using trapz which worked great until the time vector I was using didn't have enough resolution, which led me to believe it was a numerical issue rather than something fundamental. Hope this helps!
To troubleshoot your code I would plot the functions you are using and investigate, how the quad function samples them. You might be undersampling them, so make sure your minimum step size is smaller than the period of the function by at least factor 10.
I would suggest using the FFTs that are built-in to Matlab. Not only is the FFT the most efficient method to compute a spectrum (it is n*log(n) dependent on the length n of the array, whereas the integral in n^2 dependent), it will also give you automatically the frequency points that are supported by your (equally spaced) time data. If you compute the integral yourself (might be needed if datapoints are not equally spaced), you might calculate frequency data that are not resolved (closer spacing than 1/over the spacing in time, i.e. beyond the 'Fourier limit').

Call function for all elements in an array

Let's say I have a function, like:
function [result] = Square( x )
result = x * x;
end
And I have an array like the following,
x = 0:0.1:1;
I want to have an y array, which stores the squares of x's using my Square function. Sure, one way would be the following,
y = zeros(1,10);
for i = 1:10
y(i) = Square(x(i));
end
However, I guess there should be a more elegant way of doing it. I tried some of my insights and made some search, however couldn't find any solution. Any suggestions?
For the example you give:
y = x.^2; % or
y = x.*x;
in which .* and .^ are the element-wise versions of * and ^. This is the simplest, fastest way there is.
More general:
y = arrayfun(#Square, x);
which can be elegant, but it's usually pretty slow compared to
y = zeros(size(x));
for ii = 1:numel(x)
y(ii) = Square(x(ii)); end
I'd actually advise to stay away from arrayfun until profiling has showed that it is faster than a plain loop. Which will be seldom, if ever.
In new Matlab versions (R2008 and up), the JIT accelerates loops so effectively that things like arrayfun might actually disappear in a future release.
As an aside: note that I've used ii instead of i as the loop variable. In Matlab, i and j are built-in names for the imaginary unit. If you use it as a variable name, you'll lose some performance due to the necessary name resolution required. Using anything other than i or j will prevent that.
You want arrayfun.
arrayfun(#Square, x)
See help arrayfun
(tested only in GNU Octave, I do not have MATLAB)
Have you considered the element-by-element operator .*?
See the documentation for arithmetic operators.
I am going to assume that you will not be doing something as simple as a square operation and what you are trying to do is not already vectorised in MATLAB.
It is better to call the function once, and do the loop in the function. As the number of elements increase, you will notice significant increase in operation time.
Let our functions be:
function result = getSquare(x)
result = x*x; % I did not use .* on purpose
end
function result = getSquareVec(x)
result = zeros(1,numel(x));
for idx = 1:numel(x)
result(:,idx) = x(idx)*x(idx);
end
end
And let's call them from a script:
y = 1:10000;
tic;
for idx = 1:numel(y)
res = getSquare(y(idx));
end
toc
tic;
res = getSquareVec(y);
toc
I ran the code a couple of times and turns out calling the function only once is at least twice as fast.
Elapsed time is 0.020524 seconds.
Elapsed time is 0.008560 seconds.
Elapsed time is 0.019019 seconds.
Elapsed time is 0.007661 seconds.
Elapsed time is 0.022532 seconds.
Elapsed time is 0.006731 seconds.
Elapsed time is 0.023051 seconds.
Elapsed time is 0.005951 seconds.

Maximize function with fminsearch

Within my daily work, I have got to maximize a particular function making use of fminsearch; the code is:
clc
clear all
close all
f = #(x,c,k) -(x(2)/c)^3*(((exp(-(x(1)/c)^k)-exp(-(x(2)/c)^k))/((x(2)/c)^k-(x(1)/c)^k))-exp(-(x(3)/c)^k))^2;
c = 10.1;
k = 2.3;
X = fminsearch(#(x) f(x,c,k),[4,10,20]);
It works fine, as I expect, but not the issue is coming up: I need to bound x within certain limits, as:
4 < x(1) < 5
10 < x(2) < 15
20 < x(3) < 30
To achieve the proper results, I should use the optimization toolbox, that I unfortunately cannot hand.
Is there any way to get the same analysis by making use of only fminsearch?
Well, not using fminsearch directly, but if you are willing to download fminsearchbnd from the file exchange, then yes. fminsearchbnd does a bound constrained minimization of a general objective function, as an overlay on fminsearch. It calls fminsearch for you, applying bounds to the problem.
Essentially the idea is to transform your problem for you, in a way that your objective function sees as if it is solving a constrained problem. It is totally transparent. You call fminsearchbnd with a function, a starting point in the parameter space, and a set of lower and upper bounds.
For example, minimizing the rosenbrock function returns a minimum at [1,1] by fminsearch. But if we apply purely lower bounds on the problem of 2 for each variable, then fminsearchbnd finds the bound constrained solution at [2,4].
rosen = #(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
fminsearch(rosen,[3 3]) % unconstrained
ans =
1.0000 1.0000
fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained
ans =
2.0000 4.0000
If you have no constraints on a variable, then supply -inf or inf as the corresponding bound.
fminsearchbnd(rosen,[3 3],[-inf 2],[])
ans =
1.4137 2
Andrey has the right idea, and the smoother way of providing a penalty isn't hard: just add the distance to the equation.
To keep using the anonymous function:
f = #(x,c,k, Xmin, Xmax) -(x(2)/c)^3*(((exp(-(x(1)/c)^k)-exp(-(x(2)/c)^k))/((x(2)/c)^k-(x(1)/c)^k))-exp(-(x(3)/c)^k))^2 ...
+ (x< Xmin)*(Xmin' - x' + 10000) + (x>Xmax)*(x' - Xmax' + 10000) ;
The most naive way to bound x, would be giving a huge penalty for any x that is not in the range.
For example:
function res = f(x,c,k)
if x(1)>5 || x(1)<4
penalty = 1000000000000;
else
penalty = 0;
end
res = penalty - (x(2)/c)^3*(((exp(-(x(1)/c)^k)-exp(-(x(2)/c)^k))/((x(2)/c)^k-(x(1)/c)^k))-exp(-(x(3)/c)^k))^2;
end
You can improve this approach, by giving the penalty in a smoother way.

Matlab Newbie Binary Search Troubleshoot

I am a newbie to Matlab/programming in general. I wish to write a program/script that uses recursive binary search to approximate the root of $2x - 3sin(x)+5=0$, such that the iteration terminates once the truncation error is definitely $< 0.5 \times 10 ^{-5}$ and print out the number of iterations as well as the estimate of the root.
Here is my attempt that seems to have broken my computer...
%Approximating the root of f(x) = 2*x - 3*sin(x) + 5 by binary search
%Define variables
low = input('Enter lower bound of range: ');
high = input('Enter upper bound of range: ');
mid = (low + high)/2;
%Define f_low & f_high
f_low = 2*low - 3*sin(low) + 5;
f_high = 2*high - 3*sin(high) + 5;
f_mid = 2*mid - 3*sin(mid) + 5;
%Check that the entered range contains the key
while (f_low * f_high) > 0 || low > high
disp('Invalid range')
low = input('Enter lower bound of range: ');
high = input('Enter upper bound of range: ');
end
%The new range
while abs(f_mid) > 0.5*10^(-5)
if f_mid < 0
low = mid;
elseif f_mid > 0
high = mid;
end
end
fprintf('mid = %.4f \n', mid)
I haven't even added in the number-of-iterations counting bit (which I am not quite sure how to do) and already I am stuck.
Thanks for any help.
Once you set high=mid or low=mid, is mid and f_mid recalculated? It looks like you will fail if f_low>0 and f_high<0. This is a valid condition, but you are choosing the wrong one to reset in this case. Also, your termination check is on the function value, not the difference between low and high. This may be what you want, or maybe you want to check both ways. For very flat functions you may not be able to get the function value that small.
You don't need f_mid, and is in fact misleading you. You just need to calculate the value at each step, and see which direction to go.
Plus, you are just changing low and high, but you do not evaluate again f_low or f_high. Matlab is not an algebra system (there are modules for symbolic computation, but that's a different story), so you did not define f_low and f_high to change with the change of low and high: you have to reevaluate them in your final loop.