check if two matrix are equivalent [duplicate] - matlab

This question already has answers here:
Why is 24.0000 not equal to 24.0000 in MATLAB?
(6 answers)
Closed 3 years ago.
I got a problem about checking if two matrices are equal in MATLAB.
Specifically, I want to verify if, for a matrix W, all elements are equal to each other and all row sums are equal to 1 we would have W = W^2.
Therefore I wrote the following code which aims to check if every element of these two matrices are equivalent, to conclude whether the matrices are equal to each other. But it turns out that this does not work since the W8 matrix should be equal to its square.
for i = 1 :60
for j = 1 :60
if(W8(i,j) - W8_square(i,j) ~= 0)
disp('the matrix are not equal');
break;
end
end
end

There is a matlab function for it:
eq = isequal(W8,W8_square) should work
Here you find the reference
https://www.mathworks.com/help/matlab/ref/isequal.html
Be careful that if this checks for EXACT identity, so computation errors, of the order of eps, may affect the result.
To solve this, I would subtract the two matrixes and check the norm of the result: below a certain threshold (low) they are equal.
Here you have an example code for your problem:
n = 10; %matrix size
W8 = ones(n)/n; %Generating W8
W8_square = W8^2;
eq = isequal(W8,W8_square) %checking EXACT identity
M_difference = W8-W8_square; %Difference matrix
eq2 = isequal(M_difference<=eps,ones(n)) %%comparing every value with eps

Related

Optimize nested for loop for calculating xcorr of matrix rows

I have 2 nested loops which do the following:
Get two rows of a matrix
Check if indices meet a condition or not
If they do: calculate xcorr between the two rows and put it into new vector
Find the index of the maximum value of sub vector and replace element of LAG matrix with this value
I dont know how I can speed this code up by vectorizing or otherwise.
b=size(data,1);
F=size(data,2);
LAG= zeros(b,b);
for i=1:b
for j=1:b
if j>i
x=data(i,:);
y=data(j,:);
d=xcorr(x,y);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(i,j)=I-1;
d=xcorr(y,x);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(j,i)=I-1;
end
end
end
First, a note on floating point precision...
You mention in a comment that your data contains the integers 0, 1, and 2. You would therefore expect a cross-correlation to give integer results. However, since the calculation is being done in double-precision, there appears to be some floating-point error introduced. This error can cause the results to be ever so slightly larger or smaller than integer values.
Since your calculations involve looking for the location of the maxima, then you could get slightly different results if there are repeated maximal integer values with added precision errors. For example, let's say you expect the value 10 to be the maximum and appear in indices 2 and 4 of a vector d. You might calculate d one way and get d(2) = 10 and d(4) = 10.00000000000001, with some added precision error. The maximum would therefore be located in index 4. If you use a different method to calculate d, you might get d(2) = 10 and d(4) = 9.99999999999999, with the error going in the opposite direction, causing the maximum to be located in index 2.
The solution? Round your cross-correlation data first:
d = round(xcorr(x, y));
This will eliminate the floating-point errors and give you the integer results you expect.
Now, on to the actual solutions...
Solution 1: Non-loop option
You can pass a matrix to xcorr and it will perform the cross-correlation for every pairwise combination of columns. Using this, you can forego your loops altogether like so:
d = round(xcorr(data.'));
[~, I] = max(d(F:(2*F)-1,:), [], 1);
LAG = reshape(I-1, b, b).';
Solution 2: Improved loop option
There are limits to how large data can be for the above solution, since it will produce large intermediate and output variables that can exceed the maximum array size available. In such a case for loops may be unavoidable, but you can improve upon the for-loop solution above. Specifically, you can compute the cross-correlation once for a pair (x, y), then just flip the result for the pair (y, x):
% Loop over rows:
for row = 1:b
% Loop over upper matrix triangle:
for col = (row+1):b
% Cross-correlation for upper triangle:
d = round(xcorr(data(row, :), data(col, :)));
[~, I] = max(d(:, F:(2*F)-1));
LAG(row, col) = I-1;
% Cross-correlation for lower triangle:
d = fliplr(d);
[~, I] = max(d(:, F:(2*F)-1));
LAG(col, row) = I-1;
end
end

Complex vector transpose returns result with wrong signs: MATLAB [duplicate]

This question already has answers here:
Using transpose versus ctranspose in MATLAB
(4 answers)
Closed 5 years ago.
In matlab I have a matrix As
As = zeros(m, n);
Next I assign values to As and transpose the specific columns:
for idx = 1:n
% Assign value to As, then assign to 'a' and 's'
a = As(:, idx)';
s = As(:, idx);
end
Then s is a column vector like:
s = [0.1 - 0.2i
0.3 + 0.4i]
But elements in a have the flipped signs:
a = [0.1 + 0.2i, 0.3 - 0.4i]
This is confusing me, I mean the transpose of s should be a row (no problem) with the symbols in the order -, + like
a = [0.1 - 0.2i, 0.3 + 0.4i]
Can anyone tell me what the problem is?
The prime operator ' in matlab is actually an alias to ctranspose, which does not only convert rows to columns, or columns to rows of ordinary matrices or vectors, but also calculates the complex conjugate, i.e. changes the sign of the imaginary part.
The non-conjugate transpose operator A.', performs a transpose without conjugation. That is, it doesn't change the imaginary parts of the elements.

Mysterious MATLAB error using ./ in a for loop [duplicate]

This question already has answers here:
Multiple loop variables Matlab
(3 answers)
Closed 7 years ago.
I need to make a for loop in MATLAB to divide each column in a matrix by a separate column vector. I only want to do this for a selection of the columns in the matrix, not all the columns.
This is what I'd like to do, where Indexes is a 19x1 vector of integers (not all consecutive numbers), big_matrix is 82x24, and other_column is 82x1:
matrix_to_fill = zeros(82,length(Indexes));
for x = Indexes
new_column = big_matrix(:,x)./other_column;
new_index = find(Indexes==x);
matrix_to_fill(:,new_index) = new_column;
end
When I run this I get the following error:
Error using ./
Matrix dimensions must agree.
I can run each iteration separately without getting errors, so I know that the matrix dimensions agree. What's more, if I type out the Indexes as a vector it works fine:
matrix_to_fill = zeros(82,length(Indexes));
for x = [1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23]
new_column = big_matrix(:,x)./other_column;
new_index = find(Indexes==x);
matrix_to_fill(:,new_index) = new_column;
end
And I think the "x=Indexes" syntax is fine because I've tested that using just:
for x = Indexes
disp(x)
end
So I'm completely stumped. Any help would be much appreciated!
The problem is in your definition of the for loop. When you say that you think the "x=Indexes" syntax is correct you haven't been observant enough to see that it is not correct.
What you need is
for x = Indexes'
% Do your looping
end
Note the transpose in the above.
If you do
for x = Indexes
disp(x)
end
Then the loop is executed once, with x taking on the value of the whole vector.
If you do
for x = Indexes'
disp(x)
end
then x will take on the individual elements of the matrix and you'll have 19 scalars displayed, once each time through the loop.

reflecting random walk in matlab? [duplicate]

This question already has answers here:
Matlab -- random walk with boundaries, vectorized
(2 answers)
Closed 8 years ago.
I have a array of 10 vectors 'x' with as below (for simulating 1D random walk):
r=rand(10,1000);
r(r>.5)=1;
r(r<=.5)=-1;
x=cumsum(r);
The image of the one vector will be like:
If I consider 2 values in the sequence , say +10 and -10, then I would like to reflect the sequence 'x' when it reaches those values. How to achieve this?
Before answering your question, a should point that your code is broken. By default cumsum accumulate data across first dimension, to change this behavior you should specify dim parameter:
x = cumsum(r,2);
And, answering your question, you could simply invert all data above threshold:
threshold = 10;
nsteps = ceil( max(abs(x(:))) / (2*threshold) - 0.5 );
for ii = 1:nsteps
ind = abs(x) > 10;
x(ind) = 20 * sign(x(ind)) - x(ind);
end

Matlab error 'Subscript indices must either be real positive integers or logicals.' [duplicate]

This question already has answers here:
Subscript indices must either be real positive integers or logicals, generic solution
(3 answers)
Closed 8 years ago.
I am new to matlab and matlab gives error 'Subscript indices must either be real positive integers or logicals'at the last line of the code segment ( if th<0.01 || rank(A'*A)~=2) shown below, please guide me for this:
function [u,v] = optical_flow( im1,im2,windowSize )
x_c=im1(1:end-1,2:end)-im2(1:end-1,1:end-1);%(define rows 1~479,2~639 columns)-(rows 1~479,1~639)
y_c=im2(2:end,1:end-1)-im1(1:end-1,1:end-1);
t_c=im2(1:end-1,1:end-1)-im1(1:end-1,1:end-1);
%initialize for speed
u = zeros(size(x_c));
v = u;
for x = 1:size(x_c,1)-windowSize %fpr all x
for y = 1:size(x_c,2)-windowSize
%Get the windows of the dimensions
win_x=imcrop(x_c,[x y windowSize windowSize]);
win_y=imcrop(y_c,[x y windowSize windowSize]);
win_t=imcrop(t_c,[x y windowSize windowSize]);
%Convert windows to vectors to produce A for solving later
A = [win_x(:) win_y(:)];
%Compute threshold t (smallest eigenvalue of A'A)
th=min(eig(A'*A));
%Optical flow is only valid in regions with t<0.01 and
rank =2;
%if true, then it should not be computed
if th<0.01 || rank(A'*A)~=2
You assign a value to rank, which means that MATLAB now treats rank as a variable. You later treat rank as a function when you try to calculate rank(A'*A). You should rename your rank variable.
%Optical flow is only valid in regions with t<0.01 and
rank =2; % <--- RENAME THIS
%if true, then it should not be computed