How would you code this in MATLAB?
This is what I've tried, but it doesn't work quite right.
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
for k = 1:tot_it
for j = 1:n
for i = 1:n
if (j ~= i)
x(i) = -((A(i,j)/A(i,i)) * x(j) + (b(i)/A(i,i)));
else
continue;
end
end
end
end
end
j is an iterator of a sum over each i, so you need to change their order. Also the formula has a sum and in your code you're not adding anything so that's another thing to consider. The last thing I see that you're omitting is that you should save the previous state of xbecause the right side of the formula needs it. You should try something like this:
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
s = 0; %Auxiliar var to store the sum.
xold = x
for k = 1:tot_it
for i = 1:n
for j = 1:n
if (j ~= i)
s = s + (A(i,j)/A(i,i)) * xold(j);
else
continue;
end
end
x(i) = -s + b(i)/A(i,i);
s = 0;
end
xold = x;
end
end
For my studies I had to write a PDE solver for the Poisson equation on a disc shaped domain using the finite difference method.
I already passed the Lab exercise. There is one issue in my code I couldn't fix. Function fun1 with the boundary value problem gun2 is somehow oscillating at the boundary. When I use fun2 everything seems fine...
Both functions use at the boundary gun2. What is the problem?
function z = fun1(x,y)
r = sqrt(x.^2+y.^2);
z = zeros(size(x));
if( r < 0.25)
z = -10^8*exp(1./(r.^2-1/16));
end
end
function z = fun2(x,y)
z = 100*sin(2*pi*x).*sin(2*pi*y);
end
function z = gun2(x,y)
z = x.^2+y.^2;
end
function [u,A] = poisson2(funame,guname,M)
if nargin < 3
M = 50;
end
%Mesh Grid Generation
h = 2/(M + 1);
x = -1:h:1;
y = -1:h:1;
[X,Y] = meshgrid(x,y);
CI = ((X.^2 +Y.^2) < 1);
%Boundary Elements
Sum= zeros(size(CI));
%Sum over the neighbours
for i = -1:1
Sum = Sum + circshift(CI,[i,0]) + circshift(CI,[0,i]) ;
end
%if sum of neighbours larger 3 -> inner note!
CI = (Sum > 3);
%else boundary
CB = (Sum < 3 & Sum ~= 0);
Sum= zeros(size(CI));
%Sum over the boundary neighbour nodes....
for i = -1:1
Sum = Sum + circshift(CB,[i,0]) + circshift(CB,[0,i]);
end
%If the sum is equal 2 -> Diagonal boundary
CB = CB + (Sum == 2 & CB == 0 & CI == 0);
%Converting X Y to polar coordinates
Phi = atan(Y./X);
%Converting Phi R back to cartesian coordinates, only at the boundarys
for j = 1:M+2
for i = 1:M+2
if (CB(i,j)~=0)
if j > (M+2)/2
sig = 1;
else
sig = -1;
end
X(i,j) = sig*1*cos(Phi(i,j));
Y(i,j) = sig*1*sin(Phi(i,j));
end
end
end
%Numberize the internal notes u1,u2,......,un
CI = CI.*reshape(cumsum(CI(:)),size(CI));
%Number of internal notes
Ni = nnz(CI);
f = zeros(Ni,1);
k = 1;
A = spalloc(Ni,Ni,5*Ni);
%Create matix A!
for j=2:M+1
for i =2:M+1
if(CI(i,j) ~= 0)
hN = h;hS = h; hW = h; hE = h;
f(k) = fun(X(i,j),Y(i,j));
if(CB(i+1,j) ~= 0)
hN = abs(1-sqrt(X(i,j)^2+Y(i,j)^2));
f(k) = f(k) + gun(X(i,j),Y(i+1,j))*2/(hN^2+hN*h);
A(k,CI(i-1,j)) = -2/(h^2+h*hN);
else
if(CB(i-1,j) ~= 0) %in negative y is a boundry
hS = abs(1-sqrt(X(i,j)^2+Y(i,j)^2));
f(k) = f(k) + gun(X(i,j),Y(i-1,j))*2/(hS^2+h*hS);
A(k,CI(i+1,j)) = -2/(h^2+h*hS);
else
A(k,CI(i-1,j)) = -1/h^2;
A(k,CI(i+1,j)) = -1/h^2;
end
end
if(CB(i,j+1) ~= 0)
hE = abs(1-sqrt(X(i,j)^2+Y(i,j)^2));
f(k) = f(k) + gun(X(i,j+1),Y(i,j))*2/(hE^2+hE*h);
A(k,CI(i,j-1)) = -2/(h^2+h*hE);
else
if(CB(i,j-1) ~= 0)
hW = abs(1-sqrt(X(i,j)^2+Y(i,j)^2));
f(k) = f(k) + gun(X(i,j-1),Y(i,j))*2/(hW^2+h*hW);
A(k,CI(i,j+1)) = -2/(h^2+h*hW);
else
A(k,CI(i,j-1)) = -1/h^2;
A(k,CI(i,j+1)) = -1/h^2;
end
end
A(k,k) = (2/(hE*hW)+2/(hN*hS));
k = k + 1;
end
end
end
%Solve linear system
u = A\f;
U = zeros(M+2,M+2);
p = 1;
%re-arange u
for j = 1:M+2
for i = 1:M+2
if ( CI(i,j) ~= 0)
U(i,j) = u(p);
p = p+1;
else
if ( CB(i,j) ~= 0)
U(i,j) = gun(X(i,j),Y(i,j));
else
U(i,j) = NaN;
end
end
end
end
surf(X,Y,U);
end
I'm keeping this answer short for now, but may extend when the question contains more info.
My first guess is that what you are seeing is just numerical errors. Looking at the scales of the two graphs, the peaks in the first graph are relatively small compared to the signal in the second graph. Maybe there is a similar issue in the second that is just not visible because the signal is much bigger. You could try to increase the number of nodes and observe what happens with the result.
You should always expect to see numerical errors in such simulations. It's only a matter of trying to get their magnitude as small as possible (or as small as needed).
I created a fas.m script, but I'm getting wrong result.
FUNCTION
function [fnc2] = fas(x)
if x>=0 && x<1
fnc2 = x^3;
elseif x>=1 && x<2
fnc2 = 2-((x^2)/5);
elseif x>2
fnc2 = x^2+x;
elseif x<0
fprintf('x is smaller than 0, function is not defined');
end
TRAPEZOIDAL RULE SUM
clear
clc
h=0.05;
x=0.05;
x0=0;
xn=3;
while x<=2.95
fas(x);
I=0.025*(fas(x0)+2*fas(x)+fas(x0));
x=x+h;
end
Trapezoidal rule is,
so,
h = 0.05;
x = 0;
I = 0;
while x < 3
I = I + h * (fas(x) + fas(x + h)) / 2;
x = x + h;
end
disp(I);
you will get I = 11.3664 while the actual value of I is 10.3667.
So I had a problem in which I needed to find roots using the bisect method:
Function:
function [ c,k ] = bisect(f,a,b,tol)
k=0;
while b-a > tol
c=(a+b)/2;
if sign(f(c)) == sign(f(b))
b=c;
else
a=c;
end
k=k+1;
end
Script:
f = #(x) (((1800).*log((160000)./(160000 - (x.*2600))) - (9.812).*x)./750) - 1;
a = 10;
b = 50;
tol = 1e-4;
[root, iter] = bisect(f,a,b,tol);
fprintf(' iterations = %i root = %15.10e ' ,iter, root);
This works perfectly, now I need to use an embedded function in Matlab to find the value of c for different values of q (in the above example q is a fixed number 2600) from 2000 to 3000 in increments of 10 and plot x vs q. In order to do this I have the following script:
function myFunction
h = 10;
a = 10;
b = 50;
tol = 1e-4;
function y = f(x)
y = (((1800).*log((160000)./(160000 - (x.*q))) - (9.812).*x)./750) - 1;
end
for q = (2000:h:3000)
k=0;
while b-a > tol
c=(a+b)/2;
if sign(f(c)) == sign(f(b))
b=c;
cArray(q) = c;
else
a=c;
cArray(q) = c;
end
k=k+1;
end
end
plot(q,cArray)
end
This code has no errors but when I run it there is no graph. Can someone please help me with this issue? I don't even know if my code to find c vs q is correct.
Major issues with your myFunction code:
The endpoints a,b should be reset within the for loop, so that the root search begins anew.
Using q as index in cArray(q) results in a too-large array filled with zeros for indices below 2000. You need an index variable to keep track of that array. (I used j below)
plot(q,cArray) should be plot(2000:h:3000,cArray), because q is not an array, it's a scalar.
Minor issues:
You never used k
You assign to cArray(q) within the while loop; this only needs to be done once the loop has ran.
Corrected function:
function myFunction
h = 10;
tol = 1e-4;
function y = f(x)
y = (((1800).*log((160000)./(160000 - (x.*q))) - (9.812).*x)./750) - 1;
end
j = 0;
for q = 2000:h:3000
a = 10;
b = 50;
while b-a > tol
c=(a+b)/2;
if sign(f(c)) == sign(f(b))
b=c;
else
a=c;
end
end
j=j+1;
cArray(j)=c;
end
plot(2000:h:3000,cArray)
end
and its output:
I would like to know if there is some way to vectorize this code. I tried so hard to do it... but failed.
while (delta_F > e) && (i < maxLoop)
x1 = x0+d;
y0 = f(x0);
y1 = f(x1);
if y1 < y0
x0= x1;
d = a*d;
else
vF = [vF;x1];
d = -b*d;
end
i = i + 1;
if length(vF) > 1
ultm = vF(end);
pultm = vF(end-1);
delta_F = abs(ultm+pultm)/2;
end
end
It's a simple implementation of the Rosenbrock method for finding the min of a function.
In general, Matlab's vectorization works over fixed-size arrays/matrices. If you want to speed up this code in some other ways, the single biggest thing you could do is reuse your previous results in each iteration of the loop and get rid of the extraneous variables.
y0 = f(x0);
while (delta_F > e) && (i < maxLoop)
x1 = x0+d;
y1 = f(x1);
if (y1 < y0) %# new starting point, so swap points
x0 = x1;
y0 = y1;
d = a*d;
else %# same starting point, refine step and see if we're done
d = -b*d;
delta_F = abs(x1-x0)/2;
end
i = i+1;
end
This removes half the calls to f and the dynamic resizing of vF, which is horrendously slow, especially as vF gets big.