I am unable to get converging values using a Gauss-Seidel algorithm
Here is the code:
A = [12 3 -5 2
1 6 3 1
3 7 13 -1
-1 2 -1 7];
b = [2
-3
10
-11];
ep = 1e-8;
[m, n] = size(A);
[n, p] = size(b);
x = zeros(n, 1001);
x(:, 1) = []
for k=0:1000
ka = k + 1;
if ka == 1001
break;
end
xnew = zeros(n,1);
for i=1:n
sum = 0;
j = 1;
while j < i
s1 = s1 + A(i,j) * x(j, ka + 1);
j = j + 1;
end
j = i + 1;
while j <= n
sum = sum + A(i,j) * x(j, ka);
j = j + 1;
end
xnew(i) = (b(i) - sum) / A(i, i);
% if result is within error bounds exit loop
if norm(b - A * xnew, 2) < ep * norm(b, 2)
'ending'
break
end
end
x(:,ka + 1) = xnew;
end
I cannot get the A * xnew to converge on b what am I doing wrong?
I have tried running this changing the syntax several times, but I keep getting values that are way off.
Thanks!
Gabe
You have basically two problems with your code:
(1) You are using two different variables "sum" and "s1". I replaced it by mySum. By the way, dont use "sum", since there is a matlab function with this name.
(2) I think there is also a problem in the update of x;
I solved this problem and I also tried to improve your code:
(1) You dont need to save all "x"s;
(2) It is better to use a "while" than a for when you dont know how many iterations you need.
(3) It is good to use "clear all" and "close all" in general in order to keep your workspace. Sometimes old computations may generate errors. For instance, when you use matrices with different sizes and the same name.
(4) It is better to use dot/comma to separate the lines of the matrices
You still can improve this code:
(1) You can test if A is square and if it satisfies the conditions necessary to use this numerical method: to be positive definite or to be diagonally dominant.
clear all
close all
A = [12 3 -5 2;
1 6 3 1;
3 7 13 -1;
-1 2 -1 7];
b = [2;
-3;
10;
-11];
ep = 1e-8;
n = length(b); % Note this method only works for A(n,n)
xNew=zeros(n,1);
xOld=zeros(n,1);
leave=false;
while(~leave)
xOld=xNew;
for i=1:n
mySum = 0;
j = i + 1;
while j <= n
mySum = mySum + A(i,j) * xOld(j,1);
j = j + 1;
end
j = 1;
while j < i
mySum = mySum + A(i,j) * xNew(j,1);
j = j + 1;
end
mySum=b(i,1)-mySum;
xNew(i,1) = mySum / A(i, i);
end
if (norm(b - A * xNew, 2) < ep * norm(b, 2))
disp('ending');
leave=true;
end
xOld = xNew;
end
xNew
Related
I'm trying to write a matlab program to calculate an integral by means of trapezoidal and simpsons rule. The program for trapezoidal is as follows:
function [int, flag, stats] = trapComp(f, a, b, tol, hMin)
% Initialise variables
h = b - a;
n = 1;
int = h / 2 * (f(a) + f(b));
flag = 1;
if nargout == 3
stats = struct('totalErEst', [], 'totalNrIntervals', [], 'nodesList', []);
end
while h > hMin
h = h / 2;
n = 2 * n;
if h < eps % Check if h is not "zero"
break;
end
% Update the integral with the new nodes
intNew = int / 2;
for j = 1 : 2 : n
intNew = intNew + h * f(a + j * h);
end
% Estimate the error
errorEst = 1 / 3 * (int - intNew);
int = intNew;
if nargout == 3 % Update stats
stats.totalErEst = [stats.totalErEst; abs(errorEst)];
stats.totalNrIntervals = [stats.totalNrIntervals; n / 2];
end
if abs(errorEst) < tol
flag = 0;
break
end
end
end
Now simpsons rule I cant really quite get around. I know its very similar but I cant seem to figure it out.
This is my simpson code:
function [int, flag, stats] = simpComp(f, a, b, tol, hMin)
% Initialise variables
h = b - a;
n = 1;
int = h / 3 * (f(a) + 4 * f((a+b)/2) + f(b));
flag = 1;
if nargout == 3
stats = struct('totalErEst', [], 'totalNrIntervals', [], 'nodesList', []);
end
while h > hMin
h = h / 2;
n = 2 * n;
if h < eps % Check if h is not "zero"
break;
end
% Update the integral with the new nodes
intNew = int / 2;
for j = 1 : 2 : n
intNew = intNew + h * f(a + j * h);
end
% Estimate the error
errorEst = 1 / 3 * (int - intNew);
int = intNew;
if nargout == 3 % Update stats
stats.totalErEst = [stats.totalErEst; abs(errorEst)];
stats.totalNrIntervals = [stats.totalNrIntervals; n / 2];
end
if abs(errorEst) < tol
flag = 0;
break
end
end
end
Using this, however, gives an answer for an integral with a larger error than trapezoidal which i feel it shouldnt.
Any help would be appreciated
I can't seem to find a fix to my infinite loop. I have coded a Jacobi solver to solve a system of linear equations.
Here is my code:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
i =1;
for r=1:m
sum = 0;
for c=1:n
if r~=c
sum = sum + A(r,c)*x(c);
else
x(r) = (-sum + b(r))/A(r,c);
end
x(r) = (-sum + b(r))/A(r,c);
xxx end xxx
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
When I terminate the code it ends at the line with xxx
The reason why your code isn't working is due to the logic of your if statements inside your for loops. Specifically, you need to accumulate all values for a particular row that don't belong to the diagonal of that row first. Once that's done, you then perform the division. You also need to make sure that you're dividing by the diagonal coefficient of A for that row you're concentrating on, which corresponds to the component of x you're trying to solve for. You also need to remove the i=1 statement at the beginning of your loop. You're resetting i each time.
In other words:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
for r=1:m
sum = 0;
for c=1:n
if r==c %// NEW
continue;
end
sum = sum + A(r,c)*x(c); %// NEW
end
x(r) = (-sum + b(r))/A(r,r); %// CHANGE
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
Example use:
A = [6 1 1; 1 5 3; 0 2 4]
b = [1 2 3].';
[x,i] = Jacobi(A, b, [0;0;0], 1e-10)
x =
0.048780487792648
-0.085365853612062
0.792682926806031
i =
20
This means it took 20 iterations to achieve a solution with tolerance 1e-10. Compare this with MATLAB's built-in inverse:
x2 = A \ b
x2 =
0.048780487804878
-0.085365853658537
0.792682926829268
As you can see, I specified a tolerance of 1e-10, which means we are guaranteed to have 10 decimal places of accuracy. We can certainly see 10 decimal places of accuracy between what Jacobi gives us with what MATLAB gives us built-in.
V is a image matrix.D0 and D1 are right and left root of binary trees for level 1.
this is a binary tree and it has 8 level. this means a lots of code . I want to make it with recursive function.And as an Output I need all roots of means in array M. Please any idea to make it recursive?
clear all;clc;
V=imread('tire.tif');
[x y]=size(V);
U=V*0;
M=zeros(1,511);
% LEVEL 1
M(1,1)=mean(V(:));
% LEVEL 2
D0=V(V<=mean(V(:))); % right root for V
M(1,2)=mean(D0(:));
D1=V(V>mean(V(:))); %left root for V
M(1,3)=mean(D1(:));
% LEVEL 3
D00=D0(D0<=mean(D0(:))); %left root for D0
M(1,4)=mean(D00(:));
D01=D0(D0>mean(D0(:))); %left root for D0
M(1,5)=mean(D01(:));
D10=D1(D1<=mean(D1(:))); %right root for D1
M(1,6)=mean(D10(:));
D11=D1(D1>mean(D1(:))); %left root for D1
M(1,7)=mean(D11(:));
I believe this is the solution you are looking for. The tricky part is keeping track of the indices (as usual).
function M = myrecfun(V, M, n_max, n, i)
%n: current level (of recursions)
%i: an integer in [1, 2^(n-1)]
i_start = 2^n;
meanV = mean(V(:));
if n == 1
M(1) = meanV
end
DR = V(V <= meanV);
DL = V(V > meanV);
iR = i_start + 2*i - 2;
iL = i_start + 2*i - 1;
M(iR) = mean(DR);
M(iL) = mean(DL);
if n < n_max
M = myrecfun(DR, M, n_max, n+1, iR - i_start + 1);
M = myrecfun(DL, M, n_max, n+1, iL - i_start + 1);
else % else of if n < n_max
M;
end % end of if n < n_max
end % of myrecfun
Call the code:
n_max = 8;
V = 100*rand(100,100); %Just my example
M = zeros(1, 2^(n_max+1)-1);
Mout = myrecfun(V, M, n_max, 1, 1);
Test the output:
sum(Mout< 50)
ans =
256
sum(Mout > 50)
ans =
255
Hi everyone this is What I did to carry out an iteration method(gauss seidel) and I want when iteration number greater than 30 it will stop and generate the corresponding result up to 30 iteration. But I wonder why the output result were so weird and I try to check the value on the command window by typing x_ans(:,1) it gives me the correct value. It really made me frustrated why the generate result were not the same. Or any other circumstance or function can be used to set for not converging condition. Sincerely thanks in advance for every single help.
clear;clc
A = [2 8 3 1;0 2 -1 4;7 -2 1 2;-1 0 5 2]
B = [-2;4;3;5]
Es = 1e-5
n = length(B);
x = zeros(n,1);
Ea = ones(n,1);
iter = 0;
while max(Ea) >= Es
if iter <= 30
iter = iter + 1;
x_old = x;
for i = 1:n
j = 1:n;
j(i) = [];
x_cal = x;
x_cal(i) = [];
x(i) = (B(i) - sum(A(i,j) * x_cal)) / A(i,i);
end
else
break
end
x_ans(:,iter) = x;
Ea(:,iter) =abs(( x - x_old) ./ x);
end
result = [1:iter; x_ans; Ea]'
I've gone through the formulas and they are all OK. On a side note, the sum is not necessary. The problem lies with your input data - try reordering! check for example the following, which works
A = [7 -2 1 2;
2 8 3 1;
-1 0 5 2;
0 2 -1 4;]
B = [3;-2;5;4]
see the wiki under convergence.
I'm doing a homework assignment for scientific computing, specifically the iterative methods Gauss-Seidel and SOR in matlab, the problem is that for a matrix gives me unexpected results (the solution does not converge) and for another matrix converges.
Heres the code of sor, where:
A: Matrix of the system A * x = b
Xini: array of initial iteration
b: array independent of the system A * x = b
maxiter: Maximum Iterations
tol: Tolerance;
In particular, the SOR method, will receive a sixth parameter called w which corresponds to the relaxation parameter.
Here´s the code for sor method:
function [x2,iter] = sor(A,xIni, b, maxIter, tol,w)
x1 = xIni;
x2 = x1;
iter = 0;
i = 0;
j = 0;
n = size(A, 1);
for iter = 1:maxIter,
for i = 1:n
a = w / A(i,i);
x = 0;
for j = 1:i-1
x = x + (A(i,j) * x2(j));
end
for j = i+1:n
x = x + (A(i,j) * x1(j));
end
x2(i) = (a * (b(i) - x)) + ((1 - w) * x1(i));
end
x1 = x2;
if (norm(b - A * x2) < tol);
break;
end
end
Here´s the code for Gauss-seidel method:
function [x, iter] = Gauss(A, xIni, b, maxIter, tol)
x = xIni;
xnew = x;
iter = 0;
i = 0;
j = 0;
n = size(A,1);
for iter = 1:maxIter,
for i = 1:n
a = 1 / A(i,i);
x1 = 0;
x2 = 0;
for j = 1:i-1
x1 = x1 + (A(i,j) * xnew(j));
end
for j = i+1:n
x2 = x2 + (A(i,j) * x(j));
end
xnew(i) = a * (b(i) - x1 - x2);
end
x= xnew;
if ((norm(A*xnew-b)) <= tol);
break;
end
end
For this input:
A = [1 2 -2; 1 1 1; 2 2 1];
b = [1; 2; 5];
when call the function Gauss-Seidel or sor :
[x, iter] = gauss(A, [0; 0; 0], b, 1000, eps)
[x, iter] = sor(A, [0; 0; 0], b, 1000, eps, 1.5)
the output for gauss is:
x =
1.0e+304 *
1.6024
-1.6030
0.0011
iter =
1000
and for sor is:
x =
NaN
NaN
NaN
iter =
1000
however for the following system is able to find the solution:
A = [ 4 -1 0 -1 0 0;
-1 4 -1 0 -1 0;
0 -1 4 0 0 -1;
-1 0 0 4 -1 0;
0 -1 0 -1 4 -1;
0 0 -1 0 -1 4 ]
b = [1 0 0 0 0 0]'
Solution:
[x, iter] = sor(A, [0; 0; 0], b, 1000, eps, 1.5)
x =
0.2948
0.0932
0.0282
0.0861
0.0497
0.0195
iter =
52
The behavior of the methods depends on the conditioning of both matrices? because I noticed that the second matrix is better conditioned than the first. Any suggestions?
From the wiki article on Gauss-Seidel:
convergence is only guaranteed if the matrix is either diagonally dominant, or symmetric and positive definite
Since SOR is similar to Gauss-Seidel, I expect the same conditions to hold for SOR, but you might want to look that one up.
Your first matrix is definitely not diagonally dominant or symmetric. Your second matrix however, is symmetric and positive definite (because all(A==A.') and all(eig(A)>0)).
If you use Matlab's default method (A\b) as the "real" solution, and you plot the norm of the difference between each iteration and the "real" solution, then you get the two graphs below. It is obvious the first matrix is not ever going to converge, while the second matrix already produces acceptable results after a few iterations.
Always get to know the limitations of your algorithms before applying them in the wild :)