Fill odd sequences between ones in binary vector with value - arrays

I'm looking for a vectorized solution for this problem :
Let A a vector (great size : > 10000) of 0 and 1.
Ex :
A = [0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1 0 1 etc]
I want to replace the 0 between the 1's (of odd ranks) by 2
i.e. to produce :
B = [0 0 0 1 2 2 2 2 2 1 0 0 0 1 2 2 1 0 0 1 2 1 etc]
Thanks for your help

It can be done quite easily with cumsum and mod:
A = [0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 1 0 1]
Short answer
A( mod(cumsum(A),2) & ~A ) = 2
A =
0 0 0 1 2 2 2 2 2 1 0 0 0 1 2 2 1 0 0 1 2 1
You requested to fill the islands of odd rank, but by changing mod(... to ~mod(... you can easily fill also the islands of even rank.
Explanation/Old answer:
mask1 = logical(A);
mask2 = logical(mod(cumsum(A),2))
out = zeros(size(A));
out(mask2) = 2
out(mask1) = 1

try using cumsum
cs = cumsum( A );
B = 2*( mod(cs,2)== 1 );
B(A==1) = 1;

Related

Consecutive elements of a vector in matlab

I am trying to display some value of n consecutive numbers of a vector (in this example, vector x).
x = [1
1
1
1
1
1
0
0
0
0
1
1
0
0
0
0
0
0
1
0
1
0
1
0
1
0
1
1
0
0
1
1
1
1
1
1
0
0
1
1
1
1
0
0
1
1
1
1
1
1
0
0
0
0
0
1
0
0
1
0
0
0
0
1
0
0
1
0
1
0
0
0
1
0
0
0
0
1
0
1
0
0
1
0
0
0
0
1
1
0
0
0
1
0
0
0
0
0
0
1
0
1
0
0
0
0
1
0
1
0
0
0
1
0
0
0
0
0
0
1
0
0
0
1
0
0
1
1
1
1
1
1
0
0
1
1
0
0
1
0
1
0
0
0
0
0
0
1
0
1
0
0];
For example, I may want the first 3 values of 4 consecutive numbers which would be (3 values of 4 bits each):
1111
1100
0011
I may want the first 4 values of 2 consecutive numbers which would be (4 values of 2 bits each):
11
11
11
00
x is a double array. What would be an easy way to achieve this?
The simplest way is to reshape x to a matrix with your desired number of bits per value as the number of rows (MATLAB is column-major). For example, to get 4-digit values:
t = reshape(x,4,[]);
This will only work if the length of x evenly divides into 4. You could first crop x to the right number of elements to avoid errors where the length is not evenly divisible:
t = reshape(x(1:4*3),4,[]);
Now the transposed matrix t, converted to a string, looks like your desired output:
c = char(t.' + '0');
The output is a 3x4 char array:
'1111'
'1100'
'0011'
You can convert these binary representations back to numbers with bin2dec:
b = bin2dec(c);
The output is a 3-element double vector:
15
12
3

Create a matrix blockwise attaching blocks like a stairway MATLAB

I want to build an Array containing of different blocks in the following way.
Given the block I want to repeat the block n-times so that it looks like this:
A =
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
and I want the Array look like this, n times repeating the scheme:
newArray =
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
and so on...
With the free space being zeros, since the final array should be a sparse array either way.
How can I repeat and attach the block without using loops?
I'm assuming that the leftward offset of each block with respect to a pure block-diagonal matrix is the number of rows of A, as in your example.
You can build a matrix t that 2D-convolved with A gives the result, as follows:
A = [1 2 3 4; 5 6 7 8]; % data matrix
n = 3; % number of repetitions
[r, c] = size(A);
d = c-r;
t = zeros(r*(n-1)+1, d*(n-1)+1);
t(1:(r*(n-1)+1)*d+r:end) = 1;
result = conv2(t,A);
This gives
A =
1 2 3 4
5 6 7 8
result =
1 2 3 4 0 0 0 0
5 6 7 8 0 0 0 0
0 0 1 2 3 4 0 0
0 0 5 6 7 8 0 0
0 0 0 0 1 2 3 4
0 0 0 0 5 6 7 8
Here is a solution using kron:
n = 5; % number of repetitions
v = 3; % overlapping
s = size(A);
B = A(:,1:s(2)-v)
C = zeros(s(1),s(2)-v);
C(:,end-v+1:end) = A(:,end-v+1:end);
result = kron(eye(n) , B);
result(end,end+v)=0;
result(:,v+1:end) = result(:,v+1:end) + kron(eye(n) , C);
When the matrix size is large you can use sparse matrix:
n = 5;
v = 3;
s = size(A);
B = sparse(A(:,1:s(2)-v));
C = sparse(s(1),s(2)-v);
C(:,end-v+1:end) = A(:,end-v+1:end);
result = kron(eye(n) , B);
result(end,end+v) = 0;
result(:,v+1:end) = result(:,v+1:end) + kron(eye(n) , C);

Find regions of contiguous zeros in a binary array

I have
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
I want to find all the regions that have more than 5 zeros in a row. I want to find the index where it starts and where it stops.
In this case I want this: c=[12 18]. I can do it using for loops but I wonder if there is any better way, at least to find if there are some regions where this 'mask' ( mask=[0 0 0 0 0] ) appears.
A convolution based approach:
n = 5;
x = [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0];
end_idx = find(diff(conv(~x, ones(1,n))==n)==-1)
start_idx = find(diff(conv(~x, ones(1,n))==n)==1) - n + 2
returning
end_idx =
6 14 25
start_idx =
1 9 20
Note that this part is common to both lines: diff(conv(~x, ones(1,n))==n) so it would be more efficient to pull it out:
kernel = ones(1,n);
convolved = diff(conv(~x, kernel)==n);
end_idx = find(convolved==-1)
start_idx = find(convolved==1) - n + 2
You can use regexp this way:
convert the array into a string
remove the blanks
use regexp to find the sequence of 0
A possible implementation could be:
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
% Convert the array to string and remove the blanks
str=strrep(num2str(x),' ','')
% Find the occurrences
[start_idx,end_idx]=regexp(str,'0{6,}')
This gives:
start_idx = 12
end_idx = 17
where x(start_idx) is the first element of the sequence and x(end_idx) is the last one
Applied to a more long sequence, start_idx and end_idx results being arrays:
x=[0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0]
start_idx =
1 9 20
end_idx =
6 14 25

The fastest way to set up sparse matrix in matlab

I am working with iterative methods, and thus with large sparse matrices.
For instance, I want to set up a matrix like this:
1 1 0 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 0 0
0 1 1 1 0 0 1 0 0 0
0 0 1 1 1 0 0 1 0 0
1 0 0 1 1 1 0 0 1 0
0 1 0 0 1 1 1 0 0 1
So that only certain diagonals are non-zero. In my programming, I will be working with much larger matrix sizes, but Idea is the same: Only a few diagonals are non-zero, all other entries are zeros.
I know, how to do it in for loop, but it seems to be not effective, if the matrix size is large. Also I work with symmetric matrices.
I would appreciate, if you provide me a code for my sample matrix along with description.
You want spdiags:
m = 6; %// number of rows
n = 10; %// number of columns
diags = [-4 -1 0 1 4]; %// diagonals to be filled
A = spdiags(ones(min(m,n), numel(diags)), diags, m, n);
This gives:
>> full(A)
ans =
1 1 0 0 1 0 0 0 0 0
1 1 1 0 0 1 0 0 0 0
0 1 1 1 0 0 1 0 0 0
0 0 1 1 1 0 0 1 0 0
1 0 0 1 1 1 0 0 1 0
0 1 0 0 1 1 1 0 0 1

How to print an array to a text file in MATLAB

I have an array of vectors:
array = [0 0 0 0 0 0 1
0 1 1 1 0 1 0
1 1 1 1 0 0 0
.............
.............]
and I want to print it into a file as it is:
0000001
0111010
1111000
....
....
etc.
I have this but it does not seem to work:
myoutput = fopen('c:\\aitest_file.txt', 'wt');
fprintf(myoutput, '%f\n', VAA_final);
fclose(myoutput);
dlmwrite('c:\aitest_file.txt', VAA_final, 'delimiter', '');
You need to transpose your output matrix and use the appropriate number of integer identifiers:
>> VAA_final = [0 0 0 0 0 0 1; 0 1 1 1 0 1 0; 1 1 1 1 0 0 0]
VAA_final =
0 0 0 0 0 0 1
0 1 1 1 0 1 0
1 1 1 1 0 0 0
>> myoutput = fopen('aitest_file.txt', 'wt');
>> fprintf(myoutput, '%u%u%u%u%u%u%u\n', VAA_final');
>> fclose(myoutput);

Resources