I am trying to write a method that checks if a matrix is orthogonal and return TRUE if it is or FALSE if it isn't My problem is that my isequal() is not working how I want it to. Basically I can do the check in two ways based on the two formulas:
ONE way is check to see if the transpose of matrix R is equal to the inverse of matrix R. If they are equal then it is orthogonal. (R'=inv(R))
ANOTHER way is to check and see if matrix R times the transpose of matrix R equals the Identity matrix of R. (R'R=I) If yes then the matrix is orthogonal. I have most been using isequal() but it keeps yielding false. Can someone look at my code and tell me why this would be so?
I use Z=orth(randn(3,3)) to generate random orthogonal matrix and i call my method isortho(Z)
function R = isortho(r)
%isortho(R), which returns true if R is orthogonal matrix, otherwise returns false.
if ismatrix(r) && size(r,1)==size(r,2) %checks if input is square matrix
'------'
trans=transpose(r)
inverted=inv(r)
isequal(trans,inverted)
trans==inverted
isequal(transpose(r),inv(r)) %METHOD ONE
i=size(r,1);
I=eye(i) %creating Identity matrix based on size of r
r*transpose(r)
r*transpose(r)==I %METHOD TWO
%check if transpose of r is times inverse of r equals Identity matrix of r
if (r*transpose(r)==I)
R= 'True';
else
R= 'False';
end
end
end
this is my output:
>> isortho(Z)
ans =
------
trans =
-0.2579 -0.7291 -0.6339
0.8740 0.1035 -0.4747
0.4117 -0.6765 0.6106
inverted =
-0.2579 -0.7291 -0.6339
0.8740 0.1035 -0.4747
0.4117 -0.6765 0.6106
ans = ////isequal(trans,inverted) which yielded 0 false
0
ans = ////trans==inverted
0 1 0
1 0 0
0 1 1
ans = ////isequal(transpose(r),inv(r))
0
I =
1 0 0
0 1 0
0 0 1
ans =
1.0000 0 0.0000
0 1.0000 0.0000
0.0000 0.0000 1.0000
ans =
1 1 0
1 1 0
0 0 1
ans =
False
>>
could someone help me fix this or tell my why the isequal() is failing when matrix inverted and trans appear to be the same?
As stated in the comments, you are running into computer precision issues. For more detail see Why is 24.0000 not equal to 24.0000 in MATLAB? and http://matlabgeeks.com/tips-tutorials/floating-point-comparisons-in-matlab/. This is not a Matlab specific thing, it's a computer thing, and you just have to deal with it.
In your case, you are trying to see whether two things are equal, but the two things are the result of a lot of floating point operations. So they will virtually never be exactly the same, but should always be very close. So, set a tolerance, say 1e-12, and say that the two things are equal if some measure of their difference is below that tolerance, e.g.:
norm(r.'-inv(r))<tol
Which finds the 2-norm of the difference between the two matrices, and then if it is less that tol, this will evaluate to 1, or true.
If I set tol=1e-12, then everything works well. If I set tol=1e-15, everything works well. But if I set tol=1e-16, then everything stops working! This is because the amount of computer precsion error is larger than 1e-16, so the answer to norm(r.'-inv(r)) cannot be accurate to that tolerance. The smallest amount Matlab can distinguish between on my computer is roughly 2.2x10^(-16), so you have to ensure that you tolerance is set well above this value. Setting tol too large will, of course, mean you say some non-orthogonal matrices are orthogonal, but I would not expect tol=1e-14 to give you any significant issues.
Related
I have a matrix X with 3 columns. For the porous of the question X=randn(5,3).
I want to normalize the columns of X S.T. each column will have a 0 mean and a 1 std. I was using the following code:
X=(X-mean(X))./std(X);
I am getting an std of 1. My mean, however, is a very small value close to 0 but not essential 0. I tried playing a bit with the numbers to find an explanation:
X=1:15;
X=reshape(X,[5 3]);
mean(X-mean(X));
Which gives me 0 value for each column.
X=1:15;
X=reshape(X,[5 3]);
mean((X-mean(X))./std(X));
Which does not. But 0/anything is still 0. what am I missing?
Why am I not getting 0 values?
Are the values I am getting good enough for a pre-clustering algorithm normalization?
Here is a version that does what I think you're trying to do... you need to replicate the matrix because X-mean(X) isn't valid (if you're using the standard implementation)-- you can't subtract a 1x3 from a 5x3.
r = 5; c = 3;
X=randn(r,c);
Xm=repmat(mean(X),r,1);
Xstd = repmat(std(X),r,1);
Xn = (X-Xm)./Xstd;
mean(Xn)
std(Xn)
For me this prints out
ans =
1.0e-16 *
-0.6661 0 0.4441
ans =
1.0000 1.0000 1.0000
Which seems like exactly what you're looking for... note the 1e-16 multiplier on the mean values... this is essentially 0, with some floating point error.
I am facing a doubt about a comparison that I want to do between two distance matrices. Lets say that I have my ground truth matrix:
gt = [1 0 0 0 1;
0 1 0 0 1;
0 0 1 0 0;
0 0 0 1 0];
and then I have two other extracted matrices:
v1 = [0.6136 0.1012 0.1146 0.1647 0.7445;
0.2264 0.7457 -0.0015 -0.0093 1.0026;
-0.0107 0.1975 1.1219 0.1699 0.1926;
-0.0019 0.0564 0.1560 0.7723 0.0565];
v2 = [0.8209 0.1390 0.1538 0.0203 0.9997;
0.2295 0.7720 -0.0028 -0.0112 1.0329;
-0.0167 0.2593 0.8172 0.2227 0.2501;
-0.0000 0.0549 0.1561 1.2728 0.0569];
Then I want to extract the distance matrix of each column of the above matrices to the columns of the ground truth matrix gt. The way I am getting this distance is dist1 = pdist2(gt', V1','euclidean'); and dist2 = pdist2(gt', V2','euclidean');. However, the result two distance matrices are not comparable right? Since the value range of each of the v1 and v2 matrices are different, therefore I need to apply a kind of normalization in order to be able to make conclusions on the result (please correct, if I am wrong).
However, I am not sure if this should be before or after I compute the distance matrices and what type of normalization to use. The negative values are playing a role of penalizing against (for that reason I am saying that I might need to apply the normalization after I compute the distance matrix, otherwise my first pick would be to normalize the v1 and v2 before I get their distance to the gt), therefore their affect should be kept and after the normalization.
Can you please give some feedback on that, how and what type of normalization to apply.
Thanks
I read interesting article about correct memory usage in MATLAB. Here it is: Link at official website
And here I see example:
If your data contains many zeros, consider using sparse arrays, which
store only nonzero elements. The following example compares the space
required for storage of an array of mainly zeros:
A = diag(1e3,1e3); % Full matrix with ones on the diagonal
As = sparse(A) % Sparse matrix with only nonzero elements
I tried to implement it in my code and find interesting moment:
A = diag(1e3,1e3) does not create matrix with ones on the diagonal! It creates matrix of zeros with only one nonzero element:
clear A
A = diag(1e3,1e3);
find(A);
ans =
1001001
A(1001001)
ans =
1000
Ok. I read about diag function in help and see this:
D = diag(v) returns a square diagonal matrix with the elements of
vector v on the main diagonal.
Ok! So it really doesn't create diagonal matrix if v consist of 1 element! Is it mistake at help?
BUT. One more question: why it works this way?
diag(5,5)
ans =
0 0 0 0 0 5
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
I expect to get matrix 5x5 with 5 value at (1,1) or (5,5). Why it creates 6x6 matrix and why 5 is a (1,6) element?
Some time ago they fix documentation:
Manual: diag
you are using the 2nd overloaded version of diag:
D = diag(v,k) places the elements of vector v on the kth diagonal. k=0 represents the main diagonal, k>0 is above the main diagonal, and k<0 is below the main diagonal.
So your command A = diag(5,5) will construct a matrix where the diagonal elements of 5th diagonal above the main diagonal will be equal to the vector [5]. Thus the resulting value where only A(1,6) has a value.
If you want to have a 1e3x1e3 Matrix with ones on the diagonal try
A = diag(ones(1,1e3));
The article is incorrect.
A = diag(1e3,1e3);
does not produce a matrix with ones on the diagonal. The code should instead read:
A = eye(1e3,1e3);
Now reading your question again, I understood it really and have to rewrite my answer. You are refering to this part of the documentation:
A = diag(1e3,1e3); % Full matrix with ones on the diagonal
As = sparse(A) % Sparse matrix with only nonzero elements
whos
Name Size Bytes Class
A 1001x1001 8016008 double array
As 1001x1001 4020 double array (sparse)
That example is definitely wrong, probably it should be:
A=eye(1e3,1e3)
As=sparse(A);
Which creates a 1000x1000 matrix with ones on the main diagonal.
The bug is reported to mathworks
I have a matrix A which is 390 by 390 and contains numbers such as:
141270,991258825 -92423,2972762164
-92423,2972762164 60465,8168198016
139998,877391881 -91591,0460330842
30573,0969789307 -20001,7456206658 ...
If I try chol(A), Matlab fails and says that the matrix must be positive definite. Ok I saw in the API that [R,p] = chol(A) also works for negative definite matrices. I tried this, but R then becomes a 1x1 matrix. But I expect a 390x390 matrix.
The help file is slightly unclear here, but it doesn't mean that you can just use a non-positive definite matrix and get the same result by changing the way you call the function:
[R,p] = chol(A) for positive definite A, produces an upper triangular
matrix R from the diagonal and upper triangle of matrix A, satisfying
the equation R'*R=A and p is zero. If A is not positive definite, then
p is a positive integer and MATLABĀ® does not generate an error. When A
is full, R is an upper triangular matrix of order q=p-1 such that
R'*R=A(1:q,1:q).
If your matrix is not positive definite, p > 0, therefore the size of your result R will depend on p. In fact, I think this particular syntax is simply designed to allow you to use chol as a way of checking if A is positive definite, rather than just giving an error if it is not. The help file even says:
NoteĀ Using chol is preferable to using eig for determining positive definiteness.
Example - take pascal(5) and set the last element to something negative:
A =
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 -3
[R,p] = chol(A) returns
R =
1 1 1 1
0 1 2 3
0 0 1 3
0 0 0 1
p =
5
Sure enough, R'*R' == A(1:4,1:4)
By setting element X(2,2) to be negative, on the other hand, gives p of 2 and therefore a single value in R which will be sqrt(A(1,1). Setting A(1,1) to be negative returns p = 1 and an empty R.
I have encountered a problem in MatLab as I attempt to run a loop. For each iteration in the loop eigenvalues and eigenvectors for a 3x3 matrix are calculated (the matrix differs with each iteration). Further, each iteration should always yield one eigenvector of the form [0 a 0], where only the middle-value, a, is non-zero.
I need to obtain the index of the column of the eigenvector-matrix where this occurs. To do this I set up the following loop within my main-loop (where the matrix is generated):
for i = 1:3
if (eigenvectors(1,i)==0) && (eigenvectors(3,i)==0)
index_sh = i
end
end
The problem is that the eigenvector matrix in question will sometimes have an output of the form:
eigenvectors =
-0.7310 -0.6824 0
0 0 1.0000
0.6824 -0.7310 0
and in this case my code works well, and I get index_sh = 3. However, sometimes the matrix is of the form:
eigenvectors =
0.0000 0.6663 0.7457
-1.0000 0.0000 0.0000
-0.0000 -0.7457 0.6663
And in this case, MatLab does not assign any value to index_sh even though I want index_sh to be equal to 1 in this case.
If anyone knows how I can tackle this problem, so that MatLab assigns a value also when the zeros are written as 0.0000 I would be very grateful!
The problem is, very likely, that those "0.0000" are not exactly 0. To solve that, choose a tolerance and use it when comparing with 0:
tol = 1e-6;
index_sh = find(abs(eigenvectors(1,:))<tol & abs(eigenvectors(3,:))<tol);
In your code:
for ii = 1:3
if abs(eigenvectors(1,ii))<tol && abs(eigenvectors(3,ii))<tol
index_sh = i
end
end
Or, instead of a tolerance, you could choose the column whose first- and third-row entries are closer to 0:
[~, index_sh] = min(abs(eigenvectors(1,:)) + abs(eigenvectors(3,:)));