How to display column vector x in Cramer's rule in MATLAB? - matlab

I am trying to code the Cramer's Rule on MATLAB for a square matrix. I understand the Rule perfectly and also believe the logic behind my code is alright. However, could you please check where I might be going wrong that my result is not being displayed correctly? Any help would be appreciated! Thanks :)
function x = cramer(A, b)
r = size(A, 1);
c = size(A, 2);
n = size(b, 1);
if r ~= c
disp('Oops! Please enter a square matrix');
end
if r == c == n
D = det(A);
if D == 0
disp('Oops! Either, there are a family of soultions or no unique solution')
end
if D ~= 0
result = zeros(n, 1);
for (i = 1:n)
A_x = A;
A_x(:, i) = b;
Dx = det(A_x);
result(i,1) = Dx/D;
end
x = result;
end
end
end

You have an error in your if r == c == n check.
The expression r == c == n can be expanded as (r == c) == n
So it compares the value of logical(r == c) with n.
As an example:
>> 2 == 2 == 1
ans =
logical
1
Rewrite your check as r == c && c == n or isequal(r,c,n) and you should be good.
EDIT: You can simplify your logic quite some, say for example by:
function x = cramers(A, b)
if diff(size(A)) && size(A,1) == n
D = det(A);
if D == 0
disp('Oops! Either, there are a family of solutions or no unique solution')
return
else
result = zeros(n, 1);
for i = 1:n
A_x = A;
A_x(:, i) = b;
Dx = det(A_x);
result(i,1) = Dx/D;
end
x = result;
end
else
disp('Dimension error')
return
end
end

Related

NULLSPACE - RREF Command in Matlab bugs

Can someone help me debug this Matlab code? Like I have a matrix A, and I need to find A^k by diagonalization method. Below is my original code, but there is a problem with this part:
m = (M - R(i,1)*eye(NumRowsR));
disp(rref(m));
t = null(rref(m));
disp(t);
This part can't give me the nullspace of matrix t after reduced for some reasons (I recently did some research on the Internet and see some people said about the bug of rref and null). The problem is that it keeps showing me elementary matrix
1 0 0
0 1 0
0 0 1
for the eigenvalues. Does anyone know how to fix it? I will be very much appreciated!
Below is my original code, for a better view:
syms x NumRowsM NumColsM NumRowsR NumColsR NumRowst NumColst k numeigen
M = input('Input a square matrix M: ');
k = input('Input the power of matrix M: ');
[NumRowsM, NumColsM]=size(M);
if (NumRowsM ~= NumColsM)
disp('Not valid input. Matrix must be a square matrix!')
else
%Find eigenvalues:
R = solve(det(M - x*eye(NumRowsM)), x);
[NumRowsR, NumColsR] = size(R);
if (or(NumRowsR == 0,NumColsR == 0))
disp('No eigenvalues. The matrix is not diagonalizable')
else
numeigen = 0;
F = zeros(NumRowsR, NumRowsR);
d = zeros(NumRowsR,1);
for i = 1:NumRowsR
m = (M - R(i,1)*eye(NumRowsR));
disp(rref(m));
t = null(rref(m));
disp(t);
[NumRowst, NumColst] = size(t);
if (NumColst == 0)
if (i == NumRowsR && numeigen > NumRowsR)
disp('Matrix not diagonalizable due to invalid eigenvalue');
return
else
continue
end
else
numeigen = numeigen + 1;
if (NumColst == 1)
for j = 1:NumRowsR
[n, d(j)] = numden(sym(t(j,1)));
end
for j = 1:NumRowsR
F(j,i) = sym(t(j,1)) * lcm(sym(d));
end
else
for k = 1:NumColst
for j = 1:NumRowsR
[n, d(j)] = numden(sym(t(j,k)));
end
for j = 1:NumRowsR
F(j,k) = sym(t(j,k)) * lcm(sym(d));
end
end
end
end
end
disp(F);
D = (F\M)*F;
disp('The power k of the matrix M is: ');
T = F*(D^k)/(F);
disp(T)
end
end

"Spotting" probability density functions of distributions programmatically (Symbolic Toolbox)

I have a joint probability density f(x,y,z) and I wish to find the conditional distribution X|Y=y,Z=z, which is equivalent to treating x as data and y and z as parameters (constants).
For example, if I have X|Y=y,Z=z being the pdf of a N(1-2y,3z^2+2), the function would be:
syms x y z
f(y,z) = 1/sqrt(2*pi*(3*z^2+2)) * exp(-1/(2*(3*z^2+2)) * (x-(1-2*y))^2);
I would like to compare it to the following:
syms mu s L a b
Normal(mu,s) = (1/sqrt(2*pi*s^2)) * exp(-1/(2*s^2) * (x-mu)^2);
Exponential(L) = L * exp(-L*x);
Gamma(a,b) = (b^a / gamma(a)) * x^(a-1)*exp(-b*x);
Beta(a,b) = (1/beta(a,b)) * x^(a-1)*(1-x)^(b-1);
Question
How do I make a program whichDistribution that would be able to print which of these four, f is equivalent to (up to proportionality) with respect to the variable x, and what are the parameters? E.g. f and x as above, the distribution is Normal, mu=1-2*y, s=3*z^2+2.
NB: there would not always be a unique solution, since some distributions are are equivalent (e.g. Gamma(1,L)==Exponential(L))
Desired outputs
syms x y z
f = 1/sqrt(2*pi*(3*z^2+2)) * exp(-1/(2*(3*z^2+2)) * (x-(1-2*y))^2)
whichDistribution(f,x) %Conditional X|Y,Z
% Normal(1-2*y,3*z^2+2)
syms x y
f = y^(1/2)*exp(-(x^2)/2 - y/2 * (1+(4-x)^2+(6-x)^2)) % this is not a pdf because it is missing a constant of proportionality, but it should still work
whichDistribution(f,x) %Conditional X|Y
% Normal(10*y/(2*y+1), 1/(2*y+1))
whichDistribution(f,y) %Conditional Y|X
% Gamma(3/2, x^2 - 10*x + 53/2)
f = exp(-x) %also missing a constant of proportionality
whichDistribution(f,x)
% Exponential(1)
f = 1/(2*pi)*exp(-(x^2)/2 - (y^2)/2)
whichDistribution(f,x)
% Normal(0,1)
whichDistribution(f,y)
% Normal(0,1)
What I have tried so far:
Using solve():
q = solve(f(y,z) == Normal(mu,s), mu, s)
Which gives wrong results, since parameters can't depend on x:
>> q.mu
ans =
(z1^2*(log((2^(1/2)*exp(x^2/(2*z1^2) - (x + 2*y - 1)^2/(6*z^2 + 4)))/(2*pi^(1/2)*(3*z^2 + 2)^(1/2))) + pi*k*2i))/x
>> q.s
ans =
z1
Attempting to simplify f(y,z) up to proportionality (in x variable) using a propto() function that I wrote:
>> propto(f(y,z),x)
ans =
exp(-(x*(x + 4*y - 2))/(2*(3*z^2 + 2)))
>> propto(Normal(mu,s),x)
ans =
exp((x*(2*mu - x))/(2*s^2))
This is almost on the money, since it is easy to spot that s^2=3*z^2 + 2 and 2*mu=-(4*y - 2), but I don't know how to deduce this programmatically.
In case it is useful: propto(f,x) attempts to simplify f by dividing f by children of f which don't involve x, and then output whichever form has the least number of children. Here is the routine:
function out = propto(f,x)
oldf = f;
newf = propto2(f,x);
while (~strcmp(char(oldf),char(newf))) % if the form of f changed, do propto2 again. When propto2(f) == f, stop
oldf = newf;
newf = propto2(oldf,x);
end
out = newf;
end
function out = propto2(f,x)
t1 = children(expand(f)); % expanded f
i1 = ~has([t1{:}],x);
out1 = simplify(f/prod([t1{i1}])); % divides expanded f by terms that do not involve x
t2 = children(f); % unexpanded f
i2 = ~has([t2{:}],x);
out2 = simplify(f/prod([t2{i2}])); % divides f by terms that do not involve x
A = [f, symlength(f); out1, symlength(out1); out2, symlength(out2)];
A = sortrows(A,2); % outputs whichever form has the fewest number of children
out = A(1,1);
end
function L = symlength(f)
% counts the number of children of f by repeatingly applying children() to itself
t = children(f);
t = [t{:}];
L = length(t);
if (L == 1)
return
end
oldt = f;
while(~strcmp(char(oldt),char(t)))
oldt = t;
t = children(t);
t = [t{:}];
t = [t{:}];
end
L = length(t);
end
edit: added desired outputs
edit2: clarified the desired function
I have managed to solve my own problem using solve() from Symbolic Toolbox. There were two issues with my original approach: I needed to set up n simultaneous equations for n parameters, and the solve() doesn't cope well with exponentials:
solve(f(3) == g(3), f(4) == g(4), mu,s)
yields no solutions, but
logf(x) = feval(symengine,'simplify',log(f),'IgnoreAnalyticConstraints');
logg(x) = feval(symengine,'simplify',log(g),'IgnoreAnalyticConstraints');
solve(logf(3) == logg(3), logf(4) == logg(4), mu,s)
yields good solutions.
Solution
Given f(x), for each PDF g(x) we attempt to solve simultaneously
log(f(r1)) == log(g(r1)) and log(f(r2)) == log(g(r2))
for some simple non-equal numbers r1, r2. Then output g for which the solution has the lowest complexity.
The code is:
function whichDist(f,x)
syms mu s L a b x0 x1 x2 v n p g
f = propto(f,x); % simplify up to proportionality
logf(x) = feval(symengine,'simplify',log(f),'IgnoreAnalyticConstraints');
Normal(mu,s,x) = propto((1/sqrt(2*pi*s)) * exp(-1/(2*s) * (x-mu)^2),x);
Exponential(L,x) = exp(-L*x);
Gamma(a,b,x) = x^(a-1)*exp(-b*x);
Beta(a,b,x) = x^(a-1)*(1-x)^(b-1);
ChiSq(v,x) = x^(v/2 - 1) * exp(-x/2);
tdist(v,x) = (1+x^2 / v)^(-(v+1)/2);
Cauchy(g,x0,x) = 1/(1+((x-x0)/g)^2);
logf = logf(x);
best_sol = {'none', inf};
r1 = randi(10); r2 = randi(10); r3 = randi(10);
while (r1 == r2 || r2 == r3 || r1 == r3) r1 = randi(10); r2 = randi(10); r3 = randi(10); end
%% check Exponential:
if (propto(logf,x) == x) % pdf ~ exp(K*x), can read off Lambda directly
soln = -logf/x;
if (~has(soln,x)) % any solution can't depend on x
fprintf('\nExponential: rate L = %s\n\n', soln);
return
end
end
%% check Chi-sq:
if (propto(logf + x/2, log(x)) == log(x)) % can read off v directly
soln = 2*(1+(logf + x/2) / log(x));
if (~has(soln,x))
dof = feval(symengine,'simplify',soln,'IgnoreAnalyticConstraints');
fprintf('\nChi-Squared: v = %s\n\n', dof);
return
end
end
%% check t-dist:
h1 = propto(logf,x);
h = simplify(exp(h1) - 1);
if (propto(h,x^2) == x^2) % pdf ~ exp(K*x), can read off Lambda directly
soln = simplify(x^2 / h);
if (~has(soln,x))
fprintf('\nt-dist: v = %s\n\n', soln);
return
end
end
h = simplify(exp(-h1) - 1); % try again if propto flipped a sign
if (propto(h,x^2) == x^2) % pdf ~ exp(K*x), can read off Lambda directly
soln = simplify(x^2 / h);
if (~has(soln,x))
fprintf('\nt-dist: v = %s\n\n', soln);
return
end
end
%% check Normal:
logn(x) = feval(symengine,'simplify',log(Normal(mu,s,x)),'IgnoreAnalyticConstraints');
% A = (x - propto(logf/x, x))/2;
% B = simplify(-x/(logf/x - mu/s)/2);
% if (~has(A,x) && ~has(B,x))
% fprintf('Normal: mu = %s, s^2 = %s', A, B);
% return
% end
logf(x) = logf;
try % attempt to solve the equation
% solve simultaneously for two random non-equal integer values r1,r2
qn = solve(logf(r1) == logn(r1), logf(r2) == logn(r2), mu, s);
catch error
end
if (exist('qn','var')) % if solve() managed to run
if (~isempty(qn.mu) && ~isempty(qn.s) && ~any(has([qn.mu,qn.s],x))) % if solution exists
complexity = symlength(qn.mu) + symlength(qn.s);
if complexity < best_sol{2} % store best solution so far
best_sol{1} = sprintf('Normal: mu = %s, s^2 = %s', qn.mu, qn.s);
best_sol{2} = complexity;
end
end
end
%% check Cauchy:
logcau(x) = feval(symengine,'simplify',log(Cauchy(g,x0,x)),'IgnoreAnalyticConstraints');
f(x) = f;
try
qcau = solve(f(r1) == Cauchy(g,x0,r1), f(r2) == Cauchy(g,x0,r2), g, x0);
catch error
end
if (exist('qcau','var'))
if (~isempty(qcau.g) && ~isempty(qcau.x0) && ~any(has([qcau.g(1),qcau.x0(1)],x)))
complexity = symlength(qcau.g(1)) + symlength(qcau.x0(1));
if complexity < best_sol{2}
best_sol{1} = sprintf('Cauchy: g = %s, x0 = %s', qcau.g(1), qcau.x0(1));
best_sol{2} = complexity;
end
end
end
f = f(x);
%% check Gamma:
logg(x) = feval(symengine,'simplify',log(Gamma(a,b,x)),'IgnoreAnalyticConstraints');
t = children(logf); t = [t{:}];
if (length(t) == 2)
if (propto(t(1),log(x)) == log(x) && propto(t(2),x) == x)
soln = [t(1)/log(x) + 1, -t(2)/x];
if (~any(has(soln,x)))
fprintf('\nGamma: shape a = %s, rate b = %s\n\n',soln);
return
end
elseif (propto(t(2),log(x)) == log(x) && propto(t(1),x) == x)
soln = [t(2)/log(x) + 1, -t(1)/x];
if (~any(has(soln,x)))
fprintf('\nGamma: shape a = %s, rate b = %s\n\n',soln);
return
end
end
end
logf(x) = logf;
try % also try using solve(), just in case.
qg = solve(logf(r1) == logg(r1), logf(r2) == logg(r2), a, b);
catch error
end
if (exist('qg','var'))
if (~isempty(qg.a) && ~isempty(qg.b) && ~any(has([qg.a,qg.b],x)))
complexity = symlength(qg.a) + symlength(qg.b);
if complexity < best_sol{2}
best_sol{1} = sprintf('Gamma: shape a = %s, rate b = %s', qg.a, qg.b);
best_sol{2} = complexity;
end
end
end
logf = logf(x);
%% check Beta:
B = feval(symengine,'simplify',log(propto(f,x-1)),'IgnoreAnalyticConstraints');
if (propto(B,log(x-1)) == log(x-1))
B = B / log(x-1) + 1;
A = f / (x-1)^(B-1);
A = feval(symengine,'simplify',log(abs(A)),'IgnoreAnalyticConstraints');
if (propto(A,log(abs(x))) == log(abs(x)))
A = A / log(abs(x)) + 1;
if (~any(has([A,B],x)))
fprintf('\nBeta1: a = %s, b = %s\n\n', A, B);
return
end
end
elseif (propto(B,log(1-x)) == log(1-x))
B = B / log(1-x);
A = simplify(f / (1-x)^(B-1));
A = feval(symengine,'simplify',log(A),'IgnoreAnalyticConstraints');
if (propto(A,log(x)) == log(x))
A = A / log(x) + 1;
if (~any(has([A,B],x)))
fprintf('\nBeta1: a = %s, b = %s\n\n', A, B);
return
end
end
end
%% Print solution with lowest complexity
fprintf('\n%s\n\n', best_sol{1});
end
Tests:
>> syms x y z
>> f = y^(1/2)*exp(-(x^2)/2 - y/2 * (1+(4-x)^2+(6-x)^2))
>> whichDist(f,x)
Normal: mu = (10*y)/(2*y + 1), s^2 = 1/(2*y + 1)
>> whichDist(f,y)
Gamma: a = 3/2, b = x^2 - 10*x + 53/2
>> Beta(a,b,x) = propto((1/beta(a,b)) * x^(a-1)*(1-x)^(b-1), x);
>> f = Beta(1/z + 7*y/(1-sqrt(z)), z/y + 1/(1-z), x)
Beta: a = -(7*y*z - z^(1/2) + 1)/(z*(z^(1/2) - 1)), b = -(y + z - z^2)/(y*(z - 1))
All correct.
Sometimes bogus answers if the parameters are numeric:
whichDist(Beta(3,4,x),x)
Beta: a = -(pi*log(2)*1i + pi*log(3/10)*1i - log(2)*log(3/10) + log(2)*log(7/10) - log(3/10)*log(32) + log(2)*log(1323/100000))/(log(2)*(log(3/10) - log(7/10))), b = (pi*log(2)*1i + pi*log(7/10)*1i + log(2)*log(3/10) - log(2)*log(7/10) - log(7/10)*log(32) + log(2)*log(1323/100000))/(log(2)*(log(3/10) - log(7/10)))
So there is room for improvement and I will still award bounty to a better solution than this.
Edit: Added more distributions. Improved Gamma and Beta distribution identifications by spotting them directly without needing solve().

Table from a function with while loop [MATLAB]

I've written a code that gives me a zero in an interval of functions. This code uses the combination method of Newton's and Bisection methods.
Here's my code,
function p = newtonbisection(f, df, a, b, tol)
p = a;
while abs(f(p)) >= tol
if a <= p && b<= p
p = p - f(p)/df(p);
else
p = (a+b)/2;
end
if f(p)*f(b)<0
a = p;
else
b = p;
end
end
end
I've tested this code and works fine. However, if I want to create a table in .txt file with outputs {method that is used for each iter (Newton or bisection), a, b, p, f(p)} from each iteration, what should I need to add?
I could get desired data that I need in the command window (with the code below), but I'm having trouble with making an actual table with Matlab.
function p = newtonbisection(f, df, a, b, tol)
p = a;
iter = 0;
while abs(f(p)) >= tol
if a <= p && b<= p
p = p - f(p)/df(p);
iter = iter+1;
fprintf("newton\n")
else
p = (a+b)/2;
iter = iter+1;
fprintf("bisection\n")
end
if f(p)*f(b)<0
a = p;
else
b = p;
end
iter
a
b
p
disp(f(p))
end
end
Can I get some help?
There are multiple ways to do this. A simple approach would be:
preallocate your table (for performance purposes, cf. doc Preallocation)
add the corresponding values for each iteration to the table
delete remaining rows and store the table to a txt file
Example:
function p = newtonbisection(f, df, a, b, tol)
p = a;
iter = 0;
noRowsPreAll = 1000000;
sz = [noRowsPreAll 6];
varTypes = {'int32','categorical','double','double','double','double'};
varNames = {'step', 'method', 'a', 'b', 'p','f(p)'};
T = table('Size',sz,'VariableTypes',varTypes,'VariableNames', varNames);
while abs(f(p)) >= tol
iter = iter+1;
if iter > noRowsPreAll
disp('Warning: preallocate a bigger table!')
end
T.step(iter) = iter;
if a <= p && b<= p
p = p - f(p)/df(p);
T.method(iter) = 'newton';
else
p = (a+b)/2;
T.method(iter) = 'bisection';
end
if f(p)*f(b)<0
a = p;
else
b = p;
end
T.a(iter) = a;
T.b(iter) = b;
T.p(iter) = p;
T.("f(p)")(iter) = f(p);
end
T(iter+1:end,:) = [];
writetable(T, 'output.txt')
end

Poisson PDE solver on a disked shaped domain with finite difference method using matlab

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).

QR Decomposition Algorithm Using Givens Rotations

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