Matlab compare two matrixes with different dimension - matlab

I see people take ==, ~=, >, < between matrixes with a different dimension in parentheses following a matrix to get its entries, like this:
b =
1 4 7
2 5 8
3 6 9
>> b == [1 2 3]
ans =
3×3 logical array
1 0 0
0 0 0
0 0 0
>> b == [1 4 7]
ans =
3×3 logical array
1 1 1
0 0 0
0 0 0
>> b == [1 4 5]
ans =
3×3 logical array
1 1 0
0 0 0
0 0 0
>> b == [1 5 4]
ans =
3×3 logical array
1 0 0
0 1 0
0 0 0
>> a
a =
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
>> a(:, b == [1 4 5])
ans =
1 4
1 4
1 4
>> a(:, b == [1 5 4])
ans =
1 5
1 5
1 5
>> b
b =
1 4 7
2 5 8
3 6 9
>> b > [1 3 2]
ans =
3×3 logical array
0 1 1
1 1 1
1 1 1
However, I have no idea why these would work. Any explanation about this usage? (My English is not good to describe the question better, hope anyone could edit this question to make it more understandable? Thanks in advance!)

Since R2016b, MATLAB uses implicit expansion. This means that inputs' singleton dimensions (dimensions of size 1) are repeated to be the same size as other inputs.
For example:
b = [1 4 7
2 5 8
3 6 9]
%% Singleton dimension as rows
b == [x y z]
% is equivalent to
b == repmat([x y z], size(b,1), 1)
% is equivalent to
b == [x y z
x y z
x y z]
%% Singleton dimension as columns
b == [x; y; z]
% is equivalent to
b == repmat([x; y; z], 1, size(b,2))
% is equivalent to
b == [x x x
y y y
z z z]
All 3 of your examples are the "singleton dimension as rows" case, repeating your comparison row vector down and comparing to each row of b. You can easily see that the outputs are as expected.
Implicit expansion can be used in all versions of MATLAB (including pre-R2016b) with the use of bsxfun. This would look like so:
% Since 2016b
b == [1 2 3];
% All versions (#eq is the '==' equals function)
bsxfun(#eq, b, [1 2 3])

Related

Shift rows in matrix with respect to vector values in Octave/MATLAB

Can I shift rows in matrix A with respect to values in vector v?
For instance A and v specified as follows:
A =
1 0 0
1 0 0
1 0 0
v =
0 1 2
In this case I want to get this matrix from A:
A =
1 0 0
0 1 0
0 0 1
Every i-th row in A has been shifted by i-th value in v
Can I do this operation with native functions?
Or should I write it by myself?
I've tried circshift function, but I couldn't figure out how to shift rows separately.
The function circshift does not work as you want and even if you use a vector for the amount of shift, that is interpreted as the amount of shift for each dimension. While it is possible to loop over the rows of your matrix, that will not be very efficient.
More efficient is if you compute the indexing for each row which is actually quite simple:
## First, prepare all your input
octave> A = randi (9, 4, 6)
A =
8 3 2 7 4 5
4 4 7 3 9 1
1 6 3 9 2 3
7 4 1 9 5 5
octave> v = [0 2 0 1];
octave> sz = size (A);
## Compute how much shift per row, the column index (this will not work in Matlab)
octave> c_idx = mod ((0:(sz(2) -1)) .- v(:), sz(2)) +1
c_idx =
1 2 3 4 5 6
5 6 1 2 3 4
1 2 3 4 5 6
6 1 2 3 4 5
## Convert it to linear index
octave> idx = sub2ind (sz, repmat ((1:sz(1))(:), 1, sz(2)) , c_idx);
## All you need is to index
octave> A = A(idx)
A =
8 3 2 7 4 5
9 1 4 4 7 3
1 6 3 9 2 3
5 7 4 1 9 5
% A and v as above. These could be function input arguments
A = [1 0 0; 1 0 0; 1 0 0];
v = [0 1 2];
assert (all (size (v) == [1, size(A, 1)]), ...
'v needs to be a horizontal vector with as many elements as rows of A');
% Calculate shifted indices
[r, c] = size (A);
tmp = mod (repmat (0 : c-1, r, 1) - repmat (v.', 1, c), c) + 1;
Out = A(sub2ind ([r, c], repmat ([1 : r].', 1, c), tmp))
Out =
1 0 0
0 1 0
0 0 1
If performance is an issue, you can replace repmat with an equivalent bsxfun call which is more efficient (I use repmat here for simplicity to demonstrate the approach).
With focus on performance, here's one approach using bsxfun/broadcasting -
[m,n] = size(A);
idx0 = mod(bsxfun(#plus,n-v(:),1:n)-1,n);
out = A(bsxfun(#plus,(idx0*m),(1:m)'))
Sample run -
A =
1 7 5 7 7
4 8 5 7 6
4 2 6 3 2
v =
3 1 2
out =
5 7 7 1 7
6 4 8 5 7
3 2 4 2 6
Equivalent Octave version to use automatic broadcasting would look something like this -
[m,n] = size(A);
idx0 = mod( ((n-v(:)) + (1:n)) -1 ,n);
out = A((idx0*m)+(1:m)')
Shift vector with circshift in loop, iterating row index.

MATLAB: wild cards in vectors (E.g. [1,2,3,*,*,*,*])

Simple enough question, but I'm not finding a simple solution:
I want to say, "is this vector 1, 4, 7, and then 5 of whatever number?"
For example:
[1,4,7,2,6,5,8,3]
...or:
[1,4,7,2,8,5,9,2]
The final five numbers can be anything, as long as they're numbers.
Thank you!
Subscript can itself be another vector in Matlab. So you can test any values in vector:
x=zeros(1,10);
x(1)=1;x(2)=2; x(3)=3;x(6)=4;x(9)=5;
x % x = 1 2 3 0 0 4 0 0 5 0
L=[1:3,6,9]; %subscipt of vector v
y=[1, 2, 3, 4, 5];
isequal(x(L),y) % ans = 1
You can test these two conditions separately and then combine them with and.
x1 = [1,4,7,2,6,5,8,3];
is147 = all(x1(1:3)==[1,4,7]);
and(is147,length(x1)==8)
I think, for a list, the last 5 numbers have to be numeric, but if not you can put in extra tests, such as isnumeric(). Also if the input changes between column and row vectors, you can force a row vector with x_col = x1(:)
Here is a solution that will check if your variable is a vector, isvector, verify it has a length of 8 and check that the first 3 elements are [1 4 7], isequal.
>> v = [1 4 7 2 6 5 8 3];
>> isvector(v) && numel(v) == 8 && isequal(v(1:3), [1 4 7])
ans =
1
>> v = [1 4 7 2 6 5 8];
>> isvector(v) && numel(v) == 8 && isequal(v(1:3), [1 4 7])
ans =
0
>> v = [9 4 7 2 6 5 8 3];
>> isvector(v) && numel(v) == 8 && isequal(v(1:3), [1 4 7])
ans =
0
>> v = [1 4 7 2; 6 5 8 3];
>> isvector(v) && numel(v) == 8 && isequal(v(1:3), [1 4 7])
ans =
0

Permute the Matrix with Given Index

Given A is symmetry matrix with size n and
A =
1 2 3 4 5 % The Position
1 [0 5 2 4 1
2 5 0 3 0 2
3 2 3 0 0 0
4 4 0 0 0 5
5 1 2 0 5 0]
B is a row vector that permute the matrix A row and column
B = [2 4 1 5 3]
The output that I want is
C =
2 4 1 5 3 % The New Position given by Matrix B
2 [0 0 5 2 3
4 0 0 4 5 0
1 5 4 0 1 2
5 2 5 1 0 0
3 3 0 2 0 0]
I can get the output by using simple for loop
index = [2,4,1,5,3];
C = zeros(5,5);
for i = 1:5
for j = 1:5
% Position of in square matrix n
% (i,j) = (i-1)*n + j
C(i,j) = A((index(i)-1)*5+index(j));
end
end
However, if I want to permute a matrix with size 80x80, then I need to run 1600 times in order to get the output.
Is there any simple trick to do it instead of using for loop?
You should be able to rearrange your matrices as follows:
C = A(index,index);
This rearranges each dimension according to the index variable independently.

How to find one value from a matrix

0I have on matrix-
A=[1 2 2 3 5 5;
1 5 5 8 8 7;
2 9 9 3 3 5];
From matrix i need to count now many nonzero elements ,how any 1,how many 2 and how many 3 in each row of given matrix"A".For these i have written one code like:
[Ar Ac]=size(A);
for j=1:Ar
for k=1:Ac
count(:,j)=nnz(A(j,:));
d(:,j)=sum(A(j,:)== 1);
e(:,j)=sum(A(j,:)==2);
f(:,j)=sum(A(j,:)==3);
end
end
but i need to write these using on loop i.e. here i manually use sum(A(j,:)== 1),sum(A(j,:)== 2) and sum(A(j,:)== 3) but is there any option where i can only write sum(A(j,:)== 1:3) and store all the values in the different row i.e, the result will be like-
b=[1 2 1;
1 0 0;
0 1 2];
Matlab experts need your valuable suggestions
Sounds like you're looking for a histogram count:
U = unique(A);
counts = histc(A', U)';
b = counts(:, ismember(U, [1 2 3]));
Example
%// Input matrix and vector of values to count
A = [1 2 2 3 5 5; 1 5 5 8 8 7; 2 9 9 3 3 5];
vals = [1 2 3];
%// Count values
U = unique(A);
counts = histc(A', U)';
b = counts(:, ismember(U, vals));
The result is:
b =
1 2 1
1 0 0
0 1 2
Generalizing the sought values, as required by asker:
values = [ 1 2 3 ]; % or whichever values are sought
B = squeeze(sum(bsxfun(#(x,y) sum(x==y,2), A, shiftdim(values,-1)),2));
Here is a simple and general way. Just change n to however high you want to count. n=max(A(:)) is probably a good general value.
result = [];
n = 3;
for col= 1:n
result = [result, sum(A==col, 2)];
end
result
e.g. for n = 10
result =
1 2 1 0 2 0 0 0 0 0
1 0 0 0 2 0 1 2 0 0
0 1 2 0 1 0 0 0 2 0
Why not use this?
B=[];
for x=1:size(A,1)
B=[B;sum(A(x,:)==1),sum(A(x,:)==2),sum(A(x,:)==3)];
end
I'd do this way:
B = [arrayfun(#(i) find(A(i,:) == 1) , 1:3 , 'UniformOutput', false)',arrayfun(#(i) find(A(i,:) == 2) , 1:3 , 'UniformOutput', false)',arrayfun(#(i) find(A(i,:) == 3) , 1:3 , 'UniformOutput', false)'];
res = cellfun(#numel, B);
Here is a compact one:
sum(bsxfun(#eq, permute(A, [1 3 2]), 1:3),3)
You can replace 1:3 with any array.
you can make an anonymous function for it
rowcnt = #(M, R) sum(bsxfun(#eq, permute(M, [1 3 2]), R),3);
then running it on your data returns
>> rowcnt(A,1:3)
ans =
1 2 1
1 0 0
0 1 2
and for more generalized case
>> rowcnt(A,[1 2 5 8])
ans =
1 2 2 0
1 0 2 2
0 1 1 0

finding matching rows in matrix

Suppose I have an (m x n) matrix Q, and a row vector r, e.g.
Q = [ 1 2 3 ; 4 2 3 ; 5 6 7 ; 1 2 3 ; 1 2 3 ; 1 2 5 ];
r = [ 1 2 3 ];
What is the easiest way to obtain a logical vector (of length m) that indicates which of the rows in Q are identical (for all elements) to the specified row r?
In the sample case above, that should be
[ 1 0 0 1 1 0 ];
You can use ismember and do it in a single line:
>> ismember(Q,r,'rows')'
ans =
1 0 0 1 1 0
all(bsxfun(#eq, r, Q),2)'
bsxfun(#eq, r, Q) compares each row and returns a matrix with same size as Q:
>> bsxfun(#eq, r, Q)
ans =
1 1 1
0 1 1
0 0 0
1 1 1
1 1 1
1 1 0
the all function computes if the result of bsxfun is all true along each row separately. Thus it returns:
>> all(ans,2)'
ans =
1 0 0 1 1 0
and yeah, there is also a transpose operator ' to match your desired row output
a = [1 1 1; 2 2 2; 3 3 3];
b = a(1:2,;);
[temp locb] = ismember(a,b,'rows');
b(locb(locb~=0),:)
ans =
1 1 1
2 2 2
Easier way with repmat:
a = [1 2 3; 4 5 6; 7 8 9];
t = [4 5 6];
[x,y] = size(a);
r = all(a==repmat(t,y,1), 2)'