I have an assignment to do in matlab. I have to implement the modified richardson iteration. I couldn't really understand the algorithm but i came up with this:
A = [9 1 1;
2 10 3;
3 4 11];
b = [10;
19;
0];
x = [0;
0;
0];
G=eye(3)-A; %I-A
z = [0,x'];
for k=1:30
x = G*x + b;
z = [k,x'];
fprintf('Number of Iterations: %d \n', k);
display(z);
end
The output i recieve is wrong and i don't really know why. Any help is well recieved. Thanks!
You are missing the omega parameter. From the wiki page, the iteration is:
x(k+1) = x(k) + omega*( b - A*x(k) )
= (I - omega*A)*x(k) + omega*b
where omega is a scalar parameter that has to be chosen appropriately.
So you need to change your calculation of G to:
G = eye(3)-omega*A;
and the calculation of x inside the loop to:
x = G*x + omega*b;
The wiki page discusses how the value of omega can be chosen. For your particular case, omega = 0.1 seems to work well.
Consider a column vector A in Matlab containing possibly repeated integers.
Using unique, I construct the vector B containing the elements of A without repetition.
Suppose I have a vector C of size size(B,1)x1.
I would like your help to construct a vector D of size size(A,1)x1 assigning the same element of C to equal elements of A.
Let me explain better with an example.
clear
A=[2;
3;
3;
1;
4;
2;
2;
4;
5;
1];
B=unique(A,'stable');
%B=[2;
% 3;
% 1;
% 4;
% 5] %selected elements
C=[100;
101;
102;
103;
104]; %size(B,1)x1
Then, starting allocating the top elements of C to the top elements of A, I want to get
D=[100; %C(1)
101; %C(2)
101; %C(2)
102; %C(3)
103; %C(4)
100; %C(1)
100; %C(1)
103; %C(4)
104; %C(5)
102];%C(3)
I have tried to use the indices released by unique but I could'n manage to get the desired output. Any help?
You can use the second output of ismember:
[~, idx] = ismember(A,B)
D = C(idx);
Use an array function to look up the index into A of each element of B:
idxs = arrayfun(#(x)find(B==x,1),A);
D=C(idxs)
D =
100
101
101
102
103
100
100
103
104
102
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 have this function which needs to be run hundreds of times. It contains a for loop which I am trying to remove to make the function faster. Can someone help me replace the loop by a single line command.
nn = 4;
T = [5 1 2; 5 2 3; 5 3 4; 5 4 1];
p = [0 0; 1 0; 1 1; 0 1; 0.5 0.5];
A = zeros(nn,1);
for i=1:nn
sctr = T(i,:); pT = p(sctr,:);
A(i) = 1/2*det([pT,ones(3,1)]);
end
Perhaps removing det and replacing it with actual formula to calculate the determinant will help?
The For loop solution you have is probably the fastest. Other options are:
B = [p(T',:),ones(3*size(T,1),1)]
C= mat2cell(B,[3,3,3,3],3)
D= cellfun(#det,C);
or also you can write instead of D this expression
D = arrayfun(#(x) det(C{x}), 1 : size(C, 1));
etc...
I think this would work (I couldn't test it since I don't have my environment with me)
pT = p(T(1:nn,:),:);
A = 1/2 * det([pT, ones(3, 1)]);
You can obviously do a one line code from the code above but this would be less readable.
If it doesn't work and you keep the for-loop, at least consider the matrix preallocation (for A, pT and sctr) this will speed up your program.
I have the following program
format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
for i=1:500000
omegan=1.+0.0001*i;
a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0;
a(2,1) = 1; a(2,2) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(2,3) = 1; a(2,4) = 0;
a(3,1) = 0; a(3,2) = 1; a(3,3) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(3,4) = 1;
a(4,1) = 0; a(4,2) = 0; a(4,3) = 2; a(4,4) = ((omegan^2)*(Jm/(G*J))*d^2)-2;
if(abs(det(a))<1E-10) sprintf('omegan= %8.3f det= %8.3f',omegan,det(a))
end
end
Analytical solution of the above system, and the same program written in fortran gives out values of omegan equal to 16.3818 and 32.7636 (fortran values; analytical differ a little, but they're there somewhere).
So, now I'm wondering ... where am I going wrong with this ? Why is matlab not giving the expected results ?
(this is probably something terribly simple, but it's giving me headaches)
You're looking for too small of determinant values because Matlab is using a different determinant function (or some other reason like something to do with the floating point accuracy involved in the two different methods). I'll show you that Matlab is essentially giving you the correct values and a better way to approach this problem in general.
First, let's take your code and change it slightly.
format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
vals = zeros(1,500000);
for i=1:500000
omegan=1.+0.0001*i;
a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0;
a(2,1) = 1; a(2,2) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(2,3) = 1; a(2,4) = 0;
a(3,1) = 0; a(3,2) = 1; a(3,3) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(3,4) = 1;
a(4,1) = 0; a(4,2) = 0; a(4,3) = 2; a(4,4) = ((omegan^2)*(Jm/(G*J))*d^2)-2;
vals(i) = abs(det(a));
if(vals(i)<1E-10)
sprintf('omegan= %8.3f det= %8.3f',omegan,det(a))
end
end
plot(1.+0.0001*(1:500000),log(vals))
All that I've done really is logged the values of the determinant for all values of omegan and plotted the log of those determinant values as a function of omegan. Here is the plot:
You notice three major dips in the graph. Two coincide with your results of 16.3818 and 32.7636, but there is also an additional one which you were missing (probably because your condition of the determinant being less than 1e-10 was too low even for your Fortran code to pick it up). Therefore, Matlab is also telling you that those are the values of omegan that you were looking for, but because of the determinant was determined in a different manner in Matlab, the values weren't the same - not surprising when dealing with badly conditioned matrices. Also, it probably has to do with Fortran using single precision floats as someone else said. I'm not going to look into why they aren't because I don't want to waste my time on that. Instead, let's look at what you are trying to do and try a different approach.
You, as I'm sure you are aware, are trying to find the eigenvalues of the matrix
a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0 0 2 -2]];
, set them equal to
-omegan^2*(Jm/(G*J)*d^2)
and solve for omegan. This is how I went about it:
format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
C1 = (Jm/(G*J)*d^2);
a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0,0,2,-2]];
myeigs = eig(a);
myeigs(abs(myeigs) < eps) = 0.0;
for i=1:4
sprintf('omegan= %8.3f', sqrt(-myeigs(i)/C1))
end
This gives you all four solutions - not just the two that you had found with your Fortran code (though one of them, zero, was outside of your testing range for omegan ). If you want to go about solving this by checking the determinant in Matlab, as you've been trying to do, then you'll have to play with the value that you're checking the absolute value of the determinant to be less than. I got it to work for a value of 1e-4 (it gave 3 solutions: 16.382, 28.374, and 32.764).
Sorry for such a long solution, but hopefully it helps.
Update:
In my first block of code above, I replaced
vals(i) = abs(det(a));
with
[L,U] = lu(a);
s = det(L);
vals(i) = abs(s*prod(diag(U)));
which is the algorithm that det is supposedly using according to the Matlab docs. Now, I am able to use 1E-10 as the condition and it works. So maybe Matlab isn't calculating the determinant exactly as the docs say? This is kind of disturbing.
New answer:
You can investigate this problem using symbolic equations, which gives me the correct answers:
>> clear all %# Clear all existing variables
>> format long %# Display more digits of precision
>> syms Jm d omegan G J %# Your symbolic variables
>> a = ((Jm*(d*omegan)^2)/(G*J)-2).*eye(4)+... %# Create the matrix a
diag([2 1 1],1)+...
diag([1 1 2],-1);
>> solns = solve(det(a),'omegan') %# Solve for where the determinant is 0
solns =
0
0
(G*J*Jm)^(1/2)/(Jm*d)
-(G*J*Jm)^(1/2)/(Jm*d)
-(2*(G*J*Jm)^(1/2))/(Jm*d)
(2*(G*J*Jm)^(1/2))/(Jm*d)
(3^(1/2)*(G*J*Jm)^(1/2))/(Jm*d)
-(3^(1/2)*(G*J*Jm)^(1/2))/(Jm*d)
>> solns = subs(solns,{G,J,Jm,d},{8e7,77,10540,140/3}) %# Substitute values
solns =
0
0
16.381862247021893
-16.381862247021893
-32.763724494043785
32.763724494043785
28.374217734436371
-28.374217734436371
I think you either just weren't choosing values in your loop close enough to the solutions for omegan or your threshold for how close the determinant is to zero is too strict. When I plug in the given values to a, along with omegan = 16.3819 (which is the closest value to one solution your loop produces), I get this:
>> det(subs(a,{omegan,G,J,Jm,d},{16.3819,8e7,77,10540,140/3}))
ans =
2.765476845475786e-005
Which is still larger in absolute amplitude than 1e-10.
I put this as an answer because I cannot paste this into a comment: Here's how Matlab calculates the determinant. I assume the rounding errors come from calculating the product of multiple diagonal elements in U.
Algorithm
The determinant is computed from the
triangular factors obtained by
Gaussian elimination
[L,U] = lu(A) s = det(L)
%# This is always +1 or -1
det(A) = s*prod(diag(U))