Array block splitting in MATLAB - arrays

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!

Related

Why does summing the rows in this matrix give me 0?

I created an array A by first using the command A = [1:10]'.
Then I created a 10x10 matrix, only containing 0's. I then overwrote this matrix with my A, resulting in this new matrix:
A =
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0
10 0 0 0 0 0 0 0 0 0
Now the problem is, when I run the command sum((A(1,1)):(A(1,end))), I keep getting 0 when I should be getting 1, as it is the sum of the first row. I tried running the same command on other matrices and they give me the correct answer, so why isn't it working here?
The term
(A(1,1)):(A(1,end))
creates and empty array, as A(1,1) = 1 and A(1,end) = 0 which makes it impossible for colon : to create a vector, so the sum over it is zero. But its not what you want anyway, I guess.
What you supposedly want is
sum(A(1,:))
or in respect to whole matrix, by specifying the dimension of the sum, e.g.
sum(A,2)
ans =
1
2
3
4
5
6
7
8
9
10
Edit
If you want to start from a different column index you can do the following:
sum( A(rowIndex,firstColumnIndex:lastColumnIndex) )
while end can be used as macro variable for the last index of the corresponding column or row.

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

How does this Matlab/Octave code create a Boolean matrix from a vector?

The first line of code creates some vector with "discrete labels", and the second line of code creates a sparse matrix with ones at the index that the label represents. "eye" creates an identity matrix, but then even if the vector "a" is much longer, this effect of creating a sparse matrix still works!?
Could you please help me understand what is going on?
octave:4> a = [1 3 5 7 9 2 4 6 8 10]
a =
1 3 5 7 9 2 4 6 8 10
octave:5> eye(10)(a,:)
ans =
Permutation Matrix
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 1
The notation eye(10)(a,:) in Octave means: build the size-10 identity matrix (eye(10)) and then pick its rows in the order given by a (note that a is used as the first index, which corresponds to rows, and : as second index, which means "take all columns"). So, for example, the 4th row of the result is row 7 of the identity matrix, because the 4th entry of a contains 7.
From this explanation it's clear that a can be as long as you want, provided that all its values are integers in the range 1...10 (these are the rows available in eye(10)).
Note that in Matlab this "chained" indexing is not allowed. You would have to first assign eye(10) to a variable, and then index into that variable:
m = eye(10);
m(a,:)
Lastly, a minor "technical" note: the obtained matrix is not of type logical (Matlab's Boolean data type), nor is it sparse. Rather, it's a full matrix of type double.

matlab matrix from array

I have large array. Now I need a matrix with 8 elements in every row. My array looks like this:
A= Columns 1 through 18
0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0
Columns 19 through 36
0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0
and so on. How I can get [nx8] matrix? For example:
B=[0 0 0 0 0 0 0 0
0 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0]
I've tried reshape, but it didn't work correctly. I get one 1 where shouldn't be.
B=reshape(A,[],8)
You almost have it. The problem is that Matlab fills the matrix column-wise, whereas you seem to want it filled row-rise. So create an 8-row matrix and then transpose:
reshape(A,8,[]).'
What about vec2mat
vec2mat
vec2mat(A,8)

Create a "path" (for a maze) in a two-dimensional array - any algorihtm ideas?

I have a 2-dimensional array which I want to use to create a maze.
Each value can be 0 or 1 where 0 means there is a wall and 1 means there is a room. And now I need an algorithm to create a "path" within that array.
For example the blank array looks like this:
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 0 0 0 0 0 0 0
An example of a "path" would be:
0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0
0 0 0 0 1 0 1 0
0 0 0 1 1 1 1 0
0 0 0 1 0 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
It basically comes down to this:
1) Everything is 0
2) I have a random start point which will be a 1
3) From that point I need to make random adjacent values 1. BUT: There should never be a square of 4 or more adjacent fields being a 1 AND: I don't want a linear path, I want it to be a maze
(Not all the array has to be used for the maze. Infact it would be cool if I could say I want a certain amount (say 20 or 50) of rooms within that array)
Are there any good algorithms or ideas I could use for this (especially #3 of my list)?
A recursive backtracking procedure can do this.
algorithm gen-maze(pos):
set pos to 1
build a list of neighboring positions
randomly shuffle this list
for each neighbor n of pos in random order:
if n is 0 and setting it to 1 doesn't create a square:
gen-maze(n)
Start this algorithm from a random position.
For an explanation, read the Wikipedia article about depth-first search and be sure to watch the animation.

Resources