QR Decomposition Algorithm Using Givens Rotations - matlab

I am coding a QR decomposition algorithm in MATLAB, just to make sure I have the mechanics correct. Here is the code for the main function:
function [Q,R] = QRgivens(A)
n = length(A(:,1));
Q = eye(n);
R = A;
for j = 1:(n-1)
for i = n:(-1):(j+1)
G = eye(n);
[c,s] = GivensRotation( A(i-1,j),A(i,j) );
G(i-1,(i-1):i) = [c s];
G(i,(i-1):i) = [-s c];
Q = Q*G';
R = G*R;
end
end
end
The sub function GivensRotation is given below:
function [c,s] = GivensRotation(a,b)
if b == 0
c = 1;
s = 0;
else
if abs(b) > abs(a)
r = -a / b;
s = 1 / sqrt(1 + r^2);
c = s*r;
else
r = -b / a;
c = 1 / sqrt(1 + r^2);
s = c*r;
end
end
end
I've done research and I'm pretty sure this is one of the most straightforward ways to implement this decomposition, in MATLAB especially. But when I test it on a matrix A, the R produced is not right triangular as it should be. The Q is orthogonal, and Q*R = A, so the algorithm is doing some things right, but it is not producing exactly the correct factorization. Perhaps I've just been staring at the problem too long, but any insight as to what I've overlooked would be appreciated.

this seems to have more bugs,
what I see:
You should rather use [c,s] = GivensRotation( R(i-1,j),R(i,j) ); (note, R instead of A)
The original multiplications Q = Q*G'; R = G*R are correct.
r = a/b and r = b/a (without minus, not sure if it's important)
G([i-1, i],[i-1, i]) = [c -s; s c];
Here is an example code, seems to work.
First file,
% qrgivens.m
function [Q,R] = qrgivens(A)
[m,n] = size(A);
Q = eye(m);
R = A;
for j = 1:n
for i = m:-1:(j+1)
G = eye(m);
[c,s] = givensrotation( R(i-1,j),R(i,j) );
G([i-1, i],[i-1, i]) = [c -s; s c];
R = G'*R;
Q = Q*G;
end
end
end
and the second
% givensrotation.m
function [c,s] = givensrotation(a,b)
if b == 0
c = 1;
s = 0;
else
if abs(b) > abs(a)
r = a / b;
s = 1 / sqrt(1 + r^2);
c = s*r;
else
r = b / a;
c = 1 / sqrt(1 + r^2);
s = c*r;
end
end
end

Related

Compute a matrix inverse by repeatedly solving n linear systems

I am trying to solve this problem. But I keep getting an error.
This is my First Code.
% Program 3.3
function [L, U, P] = lufact(A)
[N, N] = size(A);
X = zeros(N, 1);
Y = zeros(N, 1);
C = zeros(1, N);
R = 1:N;
for p = 1: N-1
[max1, j] = max(abs(A(p:N, p)));
C = A(p,:);
A(p,:) = A(j + p - 1,:);
A(j + p -1, :) = C;
d = R(p);
R(p) = R(j + p -1);
R(j + p - 1) = d;
if A(p,p) == 0
'A is Singular. No unique Solution'
break
end
for k = p + 1:N
mult = A(k,p)/A(p,p);
A(k,p) = mult;
A(k,p + 1:N) = A(k, p + 1:N) - mult *A(p, p + 1:N);
end
I=(1:N)'*ones(1,N,1); J=I';
L = (I>J).*A + eye(N);
U = (J>=I).*A;
P = zeros(N);
for k=1:N
P(k,R(k))=1;
end
end
X(N) = Y(N)/A(N,N);
for k = N-1: -1: 1
X(k) = (Y(k) - A(k, k+1:N)*X(k+1:N))/A(k,k);
end
And This is my 2nd Code which I'm using to solve this problem.
function B = Ques3(A)
% Computes the inverse of a matrix A
[L,U,P] = lufact(A);
N = max(size(A));
I = eye(N);
B = zeros(N);
for j = 1:N
Y = forsub(L,P*I(:,j));
B(:,j) = backsub(U,Y);
end
But I keep getting an error in MATLAB,
>> Ques3(A)
Unrecognized function or variable 'forsub'.
Error in Ques3 (line 12)
Y = forsub(L,P*I(:,j));

How to display a function with double values instead of symbolic?

I want the function P to look like this:
-1 + 0.6366*(x+pi/2) + (-0.000)*(x + pi/2)*(x)
and right now it looks like this
(5734161139222659*x)/9007199254740992 + (5734161139222659*pi)/18014398509481984 - (8131029572207409*x*(x + pi/2))/324518553658426726783156020576256 - 1.
How to convert S array so that the values are not symbolic?
syms P x
f = sin(x);
f = matlabFunction(f);
X = [-pi/2, 0, pi/2];
Y = f(sym(X));
P = MetN(X,Y,x)
P = matlabFunction(P);
function [P] = MetN(X,Y,x)
n = length(X);
for i = 1:n
A(i,1) = 1;
end
for i = 2:n
for j = 2: n
if i >= j
produs = 1;
for k =1:j-1
produs = produs * (X(i) - X(k));
end
A(i,j) = produs;
end
end
end
S = SubsAsc(A, Y);
S = double(S);
disp(S);
sym produs
P = double(sym(S(1)));
for i = 2:n
produs = 1;
for j = 1:i-1
produs = produs * (x - sym(X(j)));
end
disp(produs);
P = P + double(S(i))*produs;
end
end
function [x] = SubsAsc(A,b)
n = length(b);
x(1) = (1/A(1,1))*b(1);
for k = 2:n
s = 0;
for j = 1:k-1
s = s + A(k,j)*x(j);
end
x(k) = (1/A(k,k))*(b(k)-s);
end
end
The output you currently have is because symbolic uses exact arithmetic, so it outputs it as a rational number (hence the ugly fraction).
To have it output P using decimals, use vpa(). For instance output P using decimals to 5 significant digits
>> vpa(P, 5)
ans =
0.63662*x - 2.5056e-17*x*(x + 1.5708)
This will, however, also round pi, so you can't really have the best of both worlds here.

QR factorization,matlab

%% Gram—Schmidt as Triangular Orthogonalization
clear
M = [1,1,1; 1,1,0; 1,1,9]
[m,n] = size(M);
Q = M;
Rinv = eye(n);
for i = 1:n
Ri = eye(n);
Ri(i,i) = 1 / norm(Q(:,i));
for j = i+1:n
Ri(i,j) = -Q(:,i)'*Q(:,j) / norm(Q(:,i));
end
Q = Q*Ri;
Rinv = Rinv*Ri;
end
Q
R = inv(Rinv)
The question: Q*R gives M butQ is not orthagonal.
This should return the correct result:
clear();
M = [1,1,1; 1,1,0; 1,1,9];
[m,n] = size(M);
Q = zeros(m,n);
R = zeros(n,n);
for j = 1:n
v = M(:,j);
for i = 1:j-1
R(i,j) = Q(:,i).' * M(:,j);
v = v - (R(i,j) * Q(:,i));
end
R(j,j) = norm(v);
Q(:,j) = v / R(j,j);
end
Alternatively, you could give a try to the following implementation I found on Matlab File Exchange (it contains many know variants of the algorithm): https://it.mathworks.com/matlabcentral/fileexchange/55881-gram-schmidt-orthogonalization

cant find my code error in LU decomposition [duplicate]

I am trying to implement my own LU decomposition with partial pivoting. My code is below and apparently is working fine, but for some matrices it gives different results when comparing with the built-in [L, U, P] = lu(A) function in matlab
Can anyone spot where is it wrong?
function [L, U, P] = lu_decomposition_pivot(A)
n = size(A,1);
Ak = A;
L = zeros(n);
U = zeros(n);
P = eye(n);
for k = 1:n-1
for i = k+1:n
[~,r] = max(abs(Ak(:,k)));
Ak([k r],:) = Ak([r k],:);
P([k r],:) = P([r k],:);
L(i,k) = Ak(i,k) / Ak(k,k);
for j = k+1:n
U(k,j-1) = Ak(k,j-1);
Ak(i,j) = Ak(i,j) - L(i,k)*Ak(k,j);
end
end
end
L(1:n+1:end) = 1;
U(:,end) = Ak(:,end);
return
Here are the two matrices I've tested with. The first one is correct, whereas the second has some elements inverted.
A = [1 2 0; 2 4 8; 3 -1 2];
A = [0.8443 0.1707 0.3111;
0.1948 0.2277 0.9234;
0.2259 0.4357 0.4302];
UPDATE
I have checked my code and corrected some bugs, but still there's something missing with the partial pivoting. In the first column the last two rows are always inverted (compared with the result of lu() in matlab)
function [L, U, P] = lu_decomposition_pivot(A)
n = size(A,1);
Ak = A;
L = eye(n);
U = zeros(n);
P = eye(n);
for k = 1:n-1
[~,r] = max(abs(Ak(k:end,k)));
r = n-(n-k+1)+r;
Ak([k r],:) = Ak([r k],:);
P([k r],:) = P([r k],:);
for i = k+1:n
L(i,k) = Ak(i,k) / Ak(k,k);
for j = 1:n
U(k,j) = Ak(k,j);
Ak(i,j) = Ak(i,j) - L(i,k)*Ak(k,j);
end
end
end
U(:,end) = Ak(:,end);
return
I forgot that If there was a swap in matrix P I had to swap also the matrix L. So just add the next line after after swapping P and everything will work excellent.
L([k r],:) = L([r k],:);
Both functions are not correct.
Here is the correct one.
function [L, U, P] = LU_pivot(A)
[m, n] = size(A); L=eye(n); P=eye(n); U=A;
for k=1:m-1
pivot=max(abs(U(k:m,k)))
for j=k:m
if(abs(U(j,k))==pivot)
ind=j
break;
end
end
U([k,ind],k:m)=U([ind,k],k:m)
L([k,ind],1:k-1)=L([ind,k],1:k-1)
P([k,ind],:)=P([ind,k],:)
for j=k+1:m
L(j,k)=U(j,k)/U(k,k)
U(j,k:m)=U(j,k:m)-L(j,k)*U(k,k:m)
end
pause;
end
end
My answer is here:
function [L, U, P] = LU_pivot(A)
[n, n1] = size(A); L=eye(n); P=eye(n); U=A;
for j = 1:n
[pivot m] = max(abs(U(j:n, j)));
m = m+j-1;
if m ~= j
U([m,j],:) = U([j,m], :); % interchange rows m and j in U
P([m,j],:) = P([j,m], :); % interchange rows m and j in P
if j >= 2; % very_important_point
L([m,j],1:j-1) = L([j,m], 1:j-1); % interchange rows m and j in columns 1:j-1 of L
end;
end
for i = j+1:n
L(i, j) = U(i, j) / U(j, j);
U(i, :) = U(i, :) - L(i, j)*U(j, :);
end
end

Vectorizing 4 nested for loops

I'm trying to vectorize the 2 inner nested for loops, but I can't come up with a way to do this. The FS1 and FS2 functions have been written to accept argument for N_theta and N_e, which is what the loops are iterating over
%% generate regions
for raw_r=1:visual_field_width
for raw_c=1:visual_field_width
r = raw_r - center_r;
c = raw_c - center_c;
% convert (r,c) to polar: (eccentricity, angle)
e = sqrt(r^2+c^2)*deg_per_pixel;
a = mod(atan2(r,c),2*pi);
for nt=1:N_theta
for ne=1:N_e
regions(raw_r, raw_c, nt, ne) = ...
FS_1(nt-1,a,N_theta) * ...
FS_2(ne-1,e,N_e,e0_in_deg, e_max);
end
end
end
end
Ideally, I could replace the two inner nested for loops by:
regions(raw_r,raw_c,:,:) = FS_1(:,a,N_theta) * FS_2(:,N_e,e0_in_deg,e_max);
But this isn't possible. Maybe I'm missing an easy fix or vectorization technique? e0_in_deg and e_max are parameters.
The FS_1 function is
function h = FS_1(n,theta,N,t)
if nargin==2
N = 9;
t=1/2;
elseif nargin==3
t=1/2;
end
w = (2*pi)/N;
theta = theta + w/4;
if n==0 && theta>(3/2)*pi
theta = theta - 2*pi;
end
h = FS_f((theta - (w*n + 0.5*w*(1-t)))/w);
the FS_2 function is
function g = FS_gne(n,e,N,e0, e_max)
if nargin==2
N = 10;
e0 = .5;
elseif nargin==3
e0 = .5;
end
w = (log(e_max) - log(e0))/N;
g = FS_f((log(e)-log(e0)-w*(n+1))/w);
and the FS_f function is
function f = FS_f(x, t)
if nargin<2
t = 0.5;
end
f = zeros(size(x));
% case 1
idx = x>-(1+t)/2 & x<=(t-1)/2;
f(idx) = (cos(0.5*pi*((x(idx)-(t-1)/2)/t))).^2;
% case 2
idx = x>(t-1)/2 & x<=(1-t)/2;
f(idx) = 1;
% case 3
idx = x>(1-t)/2 & x<=(1+t)/2;
f(idx) = -(cos(0.5*pi*((x(idx)-(1+t)/2)/t))).^2+1;
I had to assume values for the constants, and then used ndgrid to find the possible configurations and sub2ind to get the indices. Doing this I removed all loops. Let me know if this produced the correct values.
function RunningFunction
%% generate regions
visual_field_width = 10;
center_r = 2;
center_c = 3;
deg_per_pixel = 17;
N_theta = 2;
N_e = 5;
e0_in_deg = 35;
e_max = 17;
[raw_r, raw_c, nt, ne] = ndgrid(1:visual_field_width, 1:visual_field_width, 1:N_theta, 1:N_e);
ind = sub2ind(size(raw_r), raw_r, raw_c, nt, ne);
r = raw_r - center_r;
c = raw_c - center_c;
% convert (r,c) to polar: (eccentricity, angle)
e = sqrt(r.^2+c.^2)*deg_per_pixel;
a = mod(atan2(r,c),2*pi);
regions(ind) = ...
FS_1(nt-1,a,N_theta) .* ...
FS_2(ne-1,e,N_e,e0_in_deg, e_max);
regions = reshape(regions, size(raw_r));
end
function h = FS_1(n,theta,N,t)
if nargin==2
N = 9;
t=1/2;
elseif nargin==3
t=1/2;
end
w = (2*pi)./N;
theta = theta + w/4;
theta(n==0 & theta>(3/2)*pi) = theta(n==0 & theta>(3/2)*pi) - 2*pi;
h = FS_f((theta - (w*n + 0.5*w*(1-t)))/w);
end
function g = FS_2(n,e,N,e0, e_max)
if nargin==2
N = 10;
e0 = .5;
elseif nargin==3
e0 = .5;
end
w = (log(e_max) - log(e0))/N;
g = FS_f((log(e)-log(e0)-w*(n+1))/w);
end
function f = FS_f(x, t)
if nargin<2
t = 0.5;
end
f = zeros(size(x));
% case 1
idx = x>-(1+t)/2 & x<=(t-1)/2;
f(idx) = (cos(0.5*pi*((x(idx)-(t-1)/2)/t))).^2;
% case 2
idx = x>(t-1)/2 & x<=(1-t)/2;
f(idx) = 1;
% case 3
idx = x>(1-t)/2 & x<=(1+t)/2;
f(idx) = -(cos(0.5*pi*((x(idx)-(1+t)/2)/t))).^2+1;
end