Convert integer to logical array in MATLAB - arrays

I want to convert an integer i to a logical vector with an i-th non-zero element. That can de done with 1:10 == 2, which returns
0 1 0 0 0 0 0 0 0 0
Now, I want to vectorize this process for each row. Writing repmat(1:10, 2, 1) == [2 5]' I expect to get
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
But instead, this error occurs:
Error using ==
Matrix dimensions must agree.
Can I vectorize this process, or is a for loop the only option?

You can use bsxfun:
>> bsxfun(#eq, 1:10, [2 5].')
ans =
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
Note the transpose .' on the second vector; it's important.

Another way is to use eye and create a logical matrix that is n x n long, then use the indices to index into the rows of this matrix:
n = 10;
ind = [2 5];
E = eye(n,n) == 1;
out = E(ind, :);
We get:
>> out
out =
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0

Just another possibility using indexing:
n = 10;
ind = [2 5];
x=zeros(numel(ind),n);
x(sub2ind([numel(ind),n],1:numel(ind),ind))=1;

Related

How to copy and paste a small matrix into a bigger matrix without for-loop

For example, we have a small matrix
B = [5 2,
3 4]
and the bigger one
A = [1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1]
Now I want paste B into A so that A looks like
A = [1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 5 2
0 0 0 3 4]
That means the values of A of the bottom right has been replaced. I would like to do this without using a for-loop. How is that possible?
PS:
A is always an eye(n) matrix (n is a constant).
B is a square matrix and has a variable size but is always less or equal to A
Find the relevant row and column subscripts of A and put B there.
A(end-size(B,1)+1:end, end-size(B,2)+1:end)=B
It works even if B is not a square matrix.

Octave compare two arrays

Given two column vectors,I need to compare each element of the vector a with the first element of vector b in the first iteration and return a logical array. Then the second element of vector b with each element of vector a and return a logical array so forth. The number of logical arrays is equal to the number of elements in vector b.
a=1:10;
b=[5 6 7];
for j=1:length(b),
for i=1:10,
c=b(j)==a(i);
end;
end;
ex:
after the first iteration of inner loop need to return [0 0 0 0 1 0 0 0 0 0]
try this:
a = 1:10
b = [5 6 7]
output = zeros(3,10);
for i = 1:length(b)
output(i,:) = (a == b(:,i)) % b(:, i) meas using index get the value
end
output =
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0

Array block splitting in MATLAB

Say we have a vector containing zeros interspersed blocks of ones of varying length, such as:
0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0
I would like to transform this into a 2D array as follows. Each row contains zeros only and one of the blocks. I.e. the number of rows of the 2D array would be the number of blocks at the end. The above array would transform to:
0 0 0 1 1 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 0 1 1 1 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 1 1 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 0 1 1 1 0 0 0
I.e the first block ends up in the first row, the second block in the second row etc.
Question
This exercise is rather trivial using loops. My question is if there is a neat way using MATLAB matrix operations, MATLAB functions and array indexing to do this?
Off the top of my head you could use bwlabel (from the Image Processing Toolbox) to assign each cluster of 1's a unique value. You could then use bsxfun to check equality between the labeled version and the unique labels which will automatically expand it out into a matrix.
a = [0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0];
b = bwlabel(a);
out = bsxfun(#eq, (1:max(b))', b);
Without the image processing toolbox you could do effectively the same thing with:
C = cumsum(~a);
out = bsxfun(#eq, unique(C(logical(a))).', C);
I tried this one
N = 100; % set array size
A = randi(2,N,1)-1; % generate random array filled with 0 and 1
d = diff([0;A]); % if 1 : starting point of block
% if -1 : end point of block
ir = find(A); % Find A==1 which will be row index
ic = cumsum(d(ir)>0); % Set col index
% assemble array
% if you want output as full array
A_new = accumarray([ir,ic],ones(size(ir)),[length(A),ic(end)]);
% if you want output as sparse array
A_new = sparse(ir,ic,ones(size(ir)),length(A),ic(end),length(ir));
% display routine
figure;spy(A,'r');hold on;spy([zeros(size(A)),A_new]);
Turns out it is faster than #Suever 's solution (Compared tic toc time with size 10000, 1000 trial). Also, if you use sparse instead of accumarray, then it is much faster
Suever_time = 7~8 sec
Accumarray = 2~3 sec
Sparse = 0.2~0.3 sec
However, his one is much shorter and neat!

Check all diags in square matrix for true

I am trying to check if in a square matrix there is more than one true value in all possible diagonals and anti-diagonals, and return true, otherwise false.
So far I have tried as following but is not covering all possible diagonals:
n=8; %matrix dimension 8 x 8
diag= sum(A(1:n+1:end));
d1=diag>=2;
antiDiag=sum(A(n:n-1:end));
d2=antiDiag>=2;
if ~any(d1(:)) || ~any(d2(:))
res= true;
else
res=false;
end
this is a false:
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
this is a true:
0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 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 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Since these are my first steps in using Matlab, is there a specific function or a better way to achieve the result I am looking for?
To detect if there are more than one nonzero value in any diagonal or anti-diagonal (not just the main diagonal and antidiagonal): get the row and column indices of nonzero values, ii and jj; and then check if any value of ii-jj (diagonals) or ii+jj (anti-diagonals) is repeated:
[ii, jj] = find(A);
res = (numel(unique(ii-jj)) < numel(ii)) || (numel(unique(ii+jj)) < numel(ii));
One approach:
n=8; %// size of square matrix
A = logical(randi(2,n)-1); %// Create a logical matrix of 0s and 1s
d1 = sum(A(1:n+1:end)); %// sum all the values of Main diagonal
d2 = sum(A(n:n-1:end-1)); %// sum all the values of Main anti-diag
result = d1>=2 | d2>=2 %// result is true when any one of them is > than or = to 2
Sample run:
Inputs:
>> A
A =
0 1 1 1 1 0 1 0
0 1 1 1 1 1 0 0
0 1 0 1 1 0 0 1
0 1 1 0 1 1 0 0
0 1 0 1 1 0 0 1
1 0 0 0 1 1 0 1
1 1 1 1 1 1 0 0
1 1 1 1 0 0 0 1
Output:
result =
1
Note: This approach considers only the Main diag and Main Anti-Diag (considering the example you provided). If you want for all possible diags, the other answer from Luis Mendo is the way to go
Using #Santhan Salai's generating technique, we can use the diag function (to pull out the main diagonal of the matrix), the fliplr to flip over the center column and any to reduced to a single value.
n=8; %// size of square matrix
A = logical(randi(2,n)-1); %// Create a logical matrix of 0s and 1s
any([diag(A) ; diag(fliplr(A))])

Assign sequential number to integer element in array

Good morning/afternoon~
I have an array like this,
A= [12 0 0 0 0 3 0 0 0 66 0 0 0 0 20 0 0 2 0 31 0 0 42 0 32 0 38]
the output should be:
B= [ 1 0 0 0 0 2 0 0 0 3 0 0 0 0 4 0 0 5 0 6 0 0 7 0 8 0 9]
What should I do to replace the non-zero elements in A with sequential number?
This will do it:
A(A ~= 0) = 1:nnz(A)
A(ismember(A,A(A(:) ~=0))) = 1:numel(A(A(:) ~=0))
With the image processing toolbox (will give the same label to adjacent non-zero values, though):
B = bwlabel(A)
B = cumsum(A ~= 0) .* (A ~= 0);

Resources