Deflation in eigenvalue and eigenvector computation - matlab

Using this method, I should be able to get eigenvalues by getting the greatest value in each iteration.
But, what my code enables to get is only the first eingenvalue (and not necessarily the greatest) and I don't know where is the problem.
function [Vect,Vp]=PID(A,precision)
nbVal= 50;
[n,m]=size(A);
X=zeros(n,1);
X(1,1)=1;
Vect=zeros(n,min(n,nbVal));
Vp=zeros(1,min(n,nbVal));
XG=zeros(1,n);
j=1;
for i=1:min(nbVal,n)
Y = rand(n,1);
while (max(abs(Y/norm(Y)-X/norm(X))>=precision))
X=Y/norm(Y);
Y=A*X;
end
Vect(:,i)=X;
% To prevent a division by 0
while (X(j,1)==0 && j<=n)
j = j + 1;
end
if X(j,1)~=0
Vp(1,i) =Y(j,1)/X(j,1);
end
% Wielandt Deflation
YG= rand(1,n);
while (max(abs(YG/norm(YG)-XG/norm(XG)))>=precision )
XG=YG/norm(YG);
YG=XG*A;
end
A2=A-Vp(1,i)*(X*XG)/(XG*X);
A=A2;
end
end

Related

Continuous fraction approximation of pi

While studying for Matlab, I came up with this problem: given an integer 1<d<15 find the smallest p,q (positive integers) such that abs(p/q-pi)<=10^-d.
So here's my attempt: I first thought that I need to bound p,q in order to create loops, so I put as input data some M,Nupper bounds for p,q respectively. So here is my algorithm:
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
break
end
end
end
What is wrong about it?
Thank you in advance.
The problem lies in the the way you chose to terminate the for loops: break only stops the inner loop. Try this code instead, and check the value of p and q at which the execution stops:
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
[p,q]
error('Found!') % Arrest the program when condition is met
end
end
end
which gives the following output:
Of course, there are better ways of capturing all the possible pairs of integers that meet the condition (e.g. by using disp instead of error). That goes beyond the scope of this answer, but I shall provide a couple of examples here:
clear; clc;
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
pairs = []; % p,q pairs are stored here
k = 1; % counter
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
pairs(k,1) = p;
pairs(k,2) = q;
k = k + 1; % increment the counter
end
end
end
The script above will end quietly: the (p,q) pairs will be stored in the pair matrix.
The following one will print directly the pairs:
clear; clc;
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
out = sprintf("(%d, %d)", p,q);
disp(out);
end
end
end
For the sake of the experiment, and following up on #Cris Luengo's comment, here's a slightly more elaborate version of the script: the for loops are encapsulated in a dedicated function and a while loop keeps good track of the progress and populates the res matrix with the (p,q) pairs:
clear; clc;
M=input('Give an upper bound for p:');
N=input('Give an upper bound for q:');
d=input('Give a positive integer between 1 and 15:');
close_to_pi = #(px,qx) abs(pi-px/qx)<=10^(-d); % returns true/false
p = 1; q = 1;
count = 0;
res = nan(N*M,2) ; % (p,q) pairs are stored here; preallocate for speed!
tic % starts the timer
while (q <= N)
[p,q, found] = approx_pi(p, q, N, M, close_to_pi);
if found
count = count + 1;
res(count,:) = [p,q]; % populates output var
end
if p<M % we aren't done with p
p = p + 1;
else % reset p and increment q
p = 1;
q = q + 1;
end
end
res(isnan(res(:,1)),:) = []; % gets rid of the empty elements
disp(count)
toc % stops the timer and prints elapsed time
function [p, q, found] = approx_pi(p0, q0, N, M, fun)
for q=q0:N
for p=p0:M
if fun(p,q)
found = 1;
return
end % if
end % for p
p0 = 1;
end % for q
found = 0;
end % approx_pi
If you are interested in continuous fraction approximations of pi, try rat(pi, Tol) where Tol is the tolerance. Further details here.

Need help looping for different values of tolerance for Successive over relaxation method

I wrote the following code for a Successive over-relaxation method where it gives me the no. of iterations it took to give me the answer for a certain tolerance value.
I want help in adjusting this code so that I can get the answer for different values of tolerances i.e. [10^-4, 10^-6, 10^-8, 10^-10, 10^-12]
I know I need to put a for loop outside the existing while loop but I cannot figure out how. Can someone help me with this, please?
N=100;
ID = 30177207;% ENTER YOUR STUDENT ID HERE
[A,b]= set_A(ID,N);
xnew=linspace(0,0,length(A))';
n=size(xnew,1);
normVal=Inf;
nmax=1000; %number of maximum iterations which can be reached%
tol= 10^-4; % Tolerence for method%
iter=0;
omega = 1.7;
while normVal>tol && iter<nmax
x_old=xnew;
for i=1:n
sum1 = 0;
sum2 = 0;
for j=1:i-1 % sum the terms involving "new" values
sum1 = sum1 + A(i,j)*xnew(j);
end
for j=i+1:n % sum the terms involving "old" values
sum2 = sum2 + A(i,j)*x_old(j);
end
xnew(i) = (b(i) - sum1 - sum2)/A(i,i); % new value of x(i)
xnew = (1-omega)+ omega*xnew; %relaxation, so for omega = 1 it will give same answer as the gauss seidel method
end
iter=iter+1;
normVal=norm(x_old-xnew);
end
fprintf('Solution of the system is in %d iterations',iter);
I cannot run your code, but since you have an iterative method that runs while normVal > tol what you can do is to iterate over decreasing values of tol, and every time you leave the while loop you will have the solution within the given tolerance possibly you have the same solution for different tolerances.
N=100;
ID = 30177207;% ENTER YOUR STUDENT ID HERE
[A,b]= set_A(ID,N);
xnew=linspace(0,0,length(A))';
n=size(xnew,1);
normVal=Inf;
nmax=1000; %number of maximum iterations which can be reached%
tol= 10^-4; % Tolerence for method%
iter=0;
omega = 1.7;
for tol = [10^-4, 10^-6, 10^-8, 10^-10, 10^-12]
while normVal>tol && iter<nmax
x_old=xnew;
for i=1:n
sum1 = 0;
sum2 = 0;
for j=1:i-1 % sum the terms involving "new" values
sum1 = sum1 + A(i,j)*xnew(j);
end
for j=i+1:n % sum the terms involving "old" values
sum2 = sum2 + A(i,j)*x_old(j);
end
xnew(i) = (b(i) - sum1 - sum2)/A(i,i); % new value of x(i)
xnew = (1-omega)+ omega*xnew; %relaxation, so for omega = 1 it will give same answer as the gauss seidel method
end
iter=iter+1;
normVal=norm(x_old-xnew);
end
fprintf('here you have a solution for tol = %g', tol);
end

Finding the nth root of the bessel function of the first kind (J0(x)) using bisection

First of all, I would just like to clarify that this is an assignment for school, so I am not looking for a solution. I simply want to be pushed in the right direction.
Now, for the problem.
We have code for finding the root of a polynomial using bisection:
function [root, niter, rlist] = bisection2( func, xint, tol )
% BISECTION2: Bisection algorithm for solving a nonlinear equation
% (non-recursive).
%
% Sample usage:
% [root, niter, rlist] = bisection2( func, xint, tol )
%
% Input:
% func - function to be solved
% xint - interval [xleft,xright] bracketing the root
% tol - convergence tolerance (OPTIONAL, defaults to 1e-6)
%
% Output:
% root - final estimate of the root
% niter - number of iterations needed
% rlist - list of midpoint values obtained in each iteration.
% First, do some error checking on parameters.
if nargin < 2
fprintf( 1, 'BISECTION2: must be called with at least two arguments' );
error( 'Usage: [root, niter, rlist] = bisection( func, xint, [tol])' );
end
if length(xint) ~= 2, error( 'Parameter ''xint'' must be a vector of length 2.' ), end
if nargin < 3, tol = 1e-6; end
% fcnchk(...) allows a string function to be sent as a parameter, and
% coverts it to the correct type to allow evaluation by feval().
func = fcnchk( func );
done = 0;
rlist = [xint(1); xint(2)];
niter = 0;
while ~done
% The next line is a more accurate way of computing
% xmid = (x(1) + x(2)) / 2 that avoids cancellation error.
xmid = xint(1) + (xint(2) - xint(1)) / 2;
fmid = feval(func,xmid);
if fmid * feval(func,xint(1)) < 0
xint(2) = xmid;
else
xint(1) = xmid;
end
rlist = [rlist; xmid];
niter = niter + 1;
if abs(xint(2)-xint(1)) < 2*tol || abs(fmid) < tol
done = 1;
end
end
root = xmid;
%END bisection2.
We must use this code to find the nth zero of a Bessel function of the first kind (J0(x)). It is quite simple to insert a range and then find the specific root we are looking for. However, we must plot Xn vs. n and for that, we would need to be able to calculate a large number of roots in relation to n. So for that, I wrote this code:
bound = 1000;
x = linspace(0, bound, 1000);
for i=0:bound
for j=1:bound
y = bisection2(#(x) besselj(0,x), [i,j], 1e-6)
end
end
I believed this would work, but the roots it provides are not in order and keep repeating. The problem I believe is my range when I call bisection2. I know [i,j] is not the best way to do it and was hoping someone could lead me in the right direction on how to fix this problem.
Thank you.
Your implementation is in the right direction but it isn't completely correct.
bound = 1000;
% x = linspace(0, bound, 1000); No need of this line.
x_ini = 0; n =1;
Root = zeros(bound+1,100); % Assuming there are 100 roots in [1,1000] range
for i=0:bound
for j=1:bound
y = bisection2(#(x) besselj(i,x), [x_ini,j], 1e-6); % besselj(i,x) = Ji(x); i = 0,1,2,3,...
if abs(bessel(i,y)) < 1e-6
x_ini = y; % Finds nth root
Root(i+1,n) = y;
n = n+1;
end
end
n = 1;
end
I have replaced besselj(0,x) in your code with besselj(i,x). This gives you roots for not only J0(x) but also for J1(x), J2(x), J3(x), .....so on. (i=0,1,2,... )
Another change I made in your code is replacing [i,j] by [x_ini,j]. Initially x_ini=0 & j=1. This tries to find root in the interval [0,1]. Since the 1st root for J0 occurs at 2.4, the root your bisection function calculates (0.999) isn't actually the first root. The lines between if.....end will check if the root found by Bisection function is actually a root or not. If it is, x_ini will take the value of the root as the next root will occur after x = x_ini (or y).

Error in FDM for a coupled PDEs

Here is the code which is trying to solve a coupled PDEs using finite difference method,
clear;
Lmax = 1.0; % Maximum length
Wmax = 1.0; % Maximum wedth
Tmax = 2.; % Maximum time
% Parameters needed to solve the equation
K = 30; % Number of time steps
n = 3; % Number of space steps
m =30; % Number of space steps
M = 2;
N = 1;
Pr = 1;
Re = 1;
Gr = 5;
maxn=20; % The wave-front: intermediate point from which u=0
maxm = 20;
maxk = 20;
dt = Tmax/K;
dx = Lmax/n;
dy = Wmax/m;
%M = a*B1^2*l/(p*U)
b =1/(1+M*dt);
c =dt/(1+M*dt);
d = dt/((1+M*dt)*dy);
%Gr = gB*(T-T1)*l/U^2;
% Initial value of the function u (amplitude of the wave)
for i = 1:n
if i < maxn
u(i,1)=1.;
else
u(i,1)=0.;
end
x(i) =(i-1)*dx;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for j = 1:m
if j < maxm
v(j,1)=1.;
else
v(j,1)=0.;
end
y(j) =(j-1)*dy;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for k = 1:K
if k < maxk
T(k,1)=1.;
else
T(k,1)=0.;
end
z(k) =(k-1)*dt;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Value at the boundary
%for k=0:K
%end
% Implementation of the explicit method
for k=0:K % Time loop
for i=1:n % Space loop
for j=1:m
u(i,j,k+1) = b*u(i,j,k)+c*Gr*T(i,j,k+1)+d*[((u(i,j+1,k)-u(i,j,k))/dy)^(N-1)*((u(i,j+1,k)-u(i,j,k))/dy)]-d*[((u(i,j,k)-u(i,j-1,k))/dy)^(N-1)*((u(i,j,k)-u(i,j-1,k))/dy)]-d*[u(i,j,k)*((u(i,j,k)-u(i-1,j,k))/dx)+v(i,j,k)*((u(i,j+1,k)-u(i,j,k))/dy)];
v(i,j,k+1) = dy*[(u(i-1,j,k+1)-u(i,j,k+1))/dx]+v(i,j-1,k+1);
T(i,j,k+1) = T(i,j,k)+(dt/(Pr*Re))*{(T(i,j+1,k)-2*T(i,j,k)+T(i,j-1,k))/dy^2-Pr*Re{u(i,j,k)*((T(i,j,k)-T(i-1,j,k))/dx)+v(i,j,k)*((T(i,j+1,k)-T(i,j,k))/dy)}};
end
end
end
% Graphical representation of the wave at different selected times
plot(x,u(:,1),'-',x,u(:,10),'-',x,u(:,50),'-',x,u(:,100),'-')
title('graphs')
xlabel('X')
ylabel('Y')
But I am getting this error
Subscript indices must either be real positive integers or logicals.
I am trying to implement this
with boundary conditions
Can someone please help me out!
Thanks
To be quite honest, it looks like you started with something that's way over your head, just typed everything down in one go without thinking much, and now you are surprised that it doesn't work...
In the future, please break down problems like these into waaaay smaller chunks that you can individually plot, check, test, etc. Better yet, try simpler problems first (wave equation, heat equation, ...), gradually working your way up to this.
I say this so harshly, because there were quite a number of fairly basic things wrong with your code:
you've used braces ({}) and brackets ([]) exactly as they are written in the equation. In MATLAB, braces are a constructor for a special container object called a cell array, and brackets are used to construct arrays and matrices. To group things like in the equation, you always have to use parentheses (()).
You had quite a number of parentheses wrong, which became apparent when I re-grouped and broke up those huge unintelligible lines into multiple lines that humans can actually read with understanding
you forgot to take the absolute values in the 3rd and 4th terms of u
you looped over k = 0:K and j = 1:m and then happily index everything with k and j-1. MATLAB is 1-based, meaning, the first element of anything is element 1, and indexing with 0 is an error
you've initialized 3 vectors u, v and T, but then index those in the loop as if they are 3D arrays
Now, I've managed to come up with the following code, which runs OK and at least more or less agrees with the equations shown. But I think it still doesn't make much sense because I get only zeros out (except for the initial values).
But, with this feedback, you should be able to correct any problems left.
Lmax = 1.0; % Maximum length
Wmax = 1.0; % Maximum wedth
Tmax = 2.; % Maximum time
% Parameters needed to solve the equation
K = 30; % Number of time steps
n = 3; % Number of space steps
m = 30; % Number of space steps
M = 2;
N = 1;
Pr = 1;
Re = 1;
Gr = 5;
maxn = 20; % The wave-front: intermediate point from which u=0
maxm = 20;
maxk = 20;
dt = Tmax/K;
dx = Lmax/n;
dy = Wmax/m;
%M = a*B1^2*l/(p*U)
b = 1/(1+M*dt);
c = dt/(1+M*dt);
d = dt/((1+M*dt)*dy);
%Gr = gB*(T-T1)*l/U^2;
% Initial value of the function u (amplitude of the wave)
u = zeros(n,m,K+1);
x = zeros(n,1);
for i = 1:n
if i < maxn
u(i,1)=1.;
else
u(i,1)=0.;
end
x(i) =(i-1)*dx;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
v = zeros(n,m,K+1);
y = zeros(m,1);
for j = 1:m
if j < maxm
v(1,j,1)=1.;
else
v(1,j,1)=0.;
end
y(j) =(j-1)*dy;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
T = zeros(n,m,K+1);
z = zeros(K,1);
for k = 1:K
if k < maxk
T(1,1,k)=1.;
else
T(1,1,k)=0.;
end
z(k) =(k-1)*dt;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Value at the boundary
%for k=0:K
%end
% Implementation of the explicit method
for k = 2:K % Time loop
for i = 2:n % Space loop
for j = 2:m-1
u(i,j,k+1) = b*u(i,j,k) + ...
c*Gr*T(i,j,k+1) + ...
d*(abs(u(i,j+1,k) - u(i,j ,k))/dy)^(N-1)*((u(i,j+1,k) - u(i,j ,k))/dy) - ...
d*(abs(u(i,j ,k) - u(i,j-1,k))/dy)^(N-1)*((u(i,j ,k) - u(i,j-1,k))/dy) - ...
d*(u(i,j,k)*((u(i,j ,k) - u(i-1,j,k))/dx) +...
v(i,j,k)*((u(i,j+1,k) - u(i ,j,k))/dy));
v(i,j,k+1) = dy*(u(i-1,j,k+1)-u(i,j,k+1))/dx + ...
v(i,j-1,k+1);
T(i,j,k+1) = T(i,j,k) + dt/(Pr*Re) * (...
(T(i,j+1,k) - 2*T(i,j,k) + T(i,j-1,k))/dy^2 - Pr*Re*(...
u(i,j,k)*((T(i,j,k) - T(i-1,j,k))/dx) + v(i,j,k)*((T(i,j+1,k) - T(i,j,k))/dy))...
);
end
end
end
% Graphical representation of the wave at different selected times
figure, hold on
plot(x, u(:, 1), '-',...
x, u(:, 10), '-',...
x, u(:, 50), '-',...
x, u(:,100), '-')
title('graphs')
xlabel('X')
ylabel('Y')

How to add a Sequence of Estimates to my Newton Raphson Code for matlab?

My code works BUT I need to add 2 more things:
output- a vector containing the sequence of estimates including the initial guess x0,
input- max iterations
function [ R, E ] = myNewton( f,df,x0,tol )
i = 1;
while abs(f(x0)) >= tol
R(i) = x0;
E(i) = abs(f(x0));
i = i+1;
x0 = x0 - f(x0)/df(x0);
end
if abs(f(x0)) < tol
R(i) = x0;
E(i) = abs(f(x0));
end
end
well, everything you need is pretty much done already and you should be able to deal with it, btw..
max iteration is contained in the variable i, thus you need to return it; add this
function [ R, E , i] = myNewton( f,df,x0,tol )
Plot sequence of estimates:
plot(R); %after you call myNewton
display max number of iterations
disp(i); %after you call myNewton