Split matrix in MATLAB using predefined numbers of submatrix rows - matlab

I have a matrix A
1 1 0 0
0 1 0 0
1 0 0 1
0 0 1 0
0 0 0 0
0 1 1 1
1 1 0 0
1 0 0 0
0 0 0 1
I want this matrix to be split according to user's input say d = [1 2 3].
for i=2:length(d)
d(i) = d(i) + d(i-1); % d = [1 3 6]
end
This gives d = [1 (1+2) (1+2+3)] = d[1 3 6]. There are 9 rows in this matrix, calculate ceil of [(1/6)*9], [(3/6)*9] and [(6/6)*9]. Hence this gives [2 5 9]. First split up is first two rows , 2nd split up is next (5-2=3) 3 rows and third split is (9-5=4) 4 rows.
The output should be like:
The split up is: 1st split up->
1 1 0 0 % first 2 rows in matrix A
0 1 0 0
2nd split up->
1 0 0 1 % next 3 rows
0 0 1 0
0 0 0 0
3rd split up->
0 1 1 1 % next 4 rows
1 1 0 0
1 0 0 0
0 0 0 1

You can use mat2cell with input d = [1 2 3] to store the final splits in separate cell arrays
B = mat2cell(A, d+1, size(A,2));
or, to adapt it to your computation of the split row sizes:
d = [1 2 3];
c = cumsum(d); % [1, 3, 6]
s = ceil(size(A,1)*c/c(end)); % [2, 5, 9]
n = [s(1) diff(s)]; % [2, 3, 4]
B = mat2cell(A, n, size(A,2));
To display the splits you can add a command similar to:
cellfun(#disp, B)

Related

MATLAB: check whether next n entries of vector are less than certain value

I'm working with a large vector which contains the values of a linear combination of multiple sine functions (where the first entry is at a time of 0 miliseconds and the nth entry is at the nth miliseconds). Now I want to extract the pieces of the vector which contain (the same combination of ) sine functions, and store them separately.
Hence I want to check whether 5 entries next to each other equal zero, which means this would be a 'cut' between two separate linear combinations. If there are 5 or more entries next to each other which equal zero, the this is where the cut should be made. As an example the following (short) vector.
Let vector = [ 0 0 0 0 0 0 0 8 9 1 0 0 3 2 0 0 0 0 0 6 6 2 0 0 0 1 ] which should be cut into two separate vectors, namely
vec1= [8 9 1 0 0 3 2] and vec2= [6 6 2 0 0 0 1].
I think I could use the built-in find function but I don't think it can look for 'at least' 5 entries next to each other which equal 0, correct?
Starting with your example...
v = [ 0 0 0 0 0 0 0 8 9 1 0 0 3 2 0 0 0 0 0 6 6 2 0 0 0 1 ];
We could do the following:
% 1. Create an index `idx` which groups elements either as zeros or non-zeros,
% with an increasing group number for each subsequent set
idx = cumsum( [1, diff(v==0) ~= 0] );
% = [ 1 1 1 1 1 1 1 2 2 2 3 3 4 4 5 5 5 5 5 6 6 6 7 7 7 8 ];
% 2. Split by this group, regardless of what's in it
grps = splitapply( #(x){x}, v, idx );
% = { {1×7 double}, {1×3 double}, {1×2 double}, {1×2 double}, {1×5 double}, ... }
% 3. Get the indices for groups, incremented when the 5-zeros condition is met
zIdx = cellfun( #(x) x(1) == 0, grps ); % Just alternating 0/1, as groups alternate
idx = cellfun( #numel, grps ) >= 5 & zIdx;
idx = cumsum( idx ) .* ~idx;
% = [ 0 1 1 1 0 2 2 2 ]
% 4. Group everything together
out = arrayfun( #(x) [grps{idx==x}], 1:max(idx), 'uni', 0 );
% { [8 9 1 0 0 3 2], [6 6 2 0 0 0 1] }
I'm not sure this is any quicker than just writing a loop...
You can use regexp with the split option:
v = [0 0 0 0 0 0 0 8 90 0 0 0 0 1 0 0 3 2 0 0 0 0 0 6 6 2 0 0 0 1 ];
% vector to string then extract the subvector
r = regexp(num2str(v),'(?<![0-9])(0\s+){5,}','split')
% string to vector
out = cellfun(#str2num,r,'UniformOutput',0)
With this regular expression: (?<![1-9])(0\s+){5,}
(?<![0-9]) : check that a zero is not preceded by a digit, so 90 0 0 0 0 should not split the vector.
(0\s+){5,} : check for, at least, 5 consecutive 0.

How to create this matrix in MATLAB

I have a vector such as
A=[4;3;1;6]
and I want to create a matrix with the elements below from A
B=[6 5 4 3 2 1;4 3 2 1 0 0;3 2 1 0 0 0;1 0 0 0 0 0];
How can I do this in MATLAB ? the number of columns equal to the max of A.
Here are two ways to do this: one vectorized, and one in a loop.
A=[4;3;1;6];
B = max(bsxfun(#minus, sort(A, 'descend'), 0:(max(A)-1)), 0);
or
S = sort(A, 'descend');
m = numel(A); n = S(1);
C = zeros(m,n);
for k = 1:m
C(k,1:S(k)) = S(k):-1:1;
end
Results:
B =
6 5 4 3 2 1
4 3 2 1 0 0
3 2 1 0 0 0
1 0 0 0 0 0

Loopless submatrix assignment in Matlab

I have a matrix F of size D-by-N and a vector A of length N of random integers in the range [1,a]. I want to create a matrix M of size D * a such that each colum M(:,i) has the vector F(:,i) starting from the index (A(i)-1)*D+1 to (A(i)-1)*D+D.
Example:
F = [1 2 3 10
4 5 6 22]
A = [3 2 1 2]
a = 4
M = [0 0 3 0
0 0 6 0
0 2 0 10
0 5 0 22
1 0 0 0
4 0 0 0
0 0 0 0
0 0 0 0]
I can do it with a simple loop
for i = 1 : N
M((A(i)-1)*D+1:(A(i)-1)*D+D,i) = F(:,i);
end
but for large N this might take a while. I am looking for a way to do it without loop.
You can use bsxfun for a linear-indexing based approach -
[D,N] = size(F); %// Get size of F
start_idx = (A-1)*D+1 + [0:N-1]*D*a; %// column start linear indices
all_idx = bsxfun(#plus,start_idx,[0:D-1]'); %//'# all linear indices
out = zeros(D*a,N); %// Initialize output array with zeros
out(all_idx) = F; %// Insert values from F into output array
Sample run -
F =
1 2 3 10
4 5 6 22
A =
3 2 1 2
a =
4
out =
0 0 3 0
0 0 6 0
0 2 0 10
0 5 0 22
1 0 0 0
4 0 0 0
0 0 0 0
0 0 0 0

How to generate a matrix of vector combinations with zeros for excluded elements?

I want to create a matrix from all combinations of elements of one vector that fulfill a condition
For example, I have this vector
a = [1 2 3 4 5]
and want to create a matrix like
a = [1 0 0 0 0;
1 2 0 0 0;
1 2 3 0 0;
1 2 3 4 0;
1 2 3 4 5;
0 2 0 0 0;
0 2 3 0 0;
........;]
and then get the rows that fulfill the condition I can use the command:
b = sum(a')' > value
but I don't know how to generate the matrix
You can generate all possible binary combinations to determine the matrix you want:
a = [1 2 3];
n = size(a,2);
% generate bit combinations
c =(dec2bin(0:(2^n)-1)=='1');
% remove first line
c = c(2:end,:)
n_c = size(c,1);
a_rep = repmat(a,n_c,1);
result = c .* a_rep
Output:
c =
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
result =
0 0 3
0 2 0
0 2 3
1 0 0
1 0 3
1 2 0
1 2 3

Matlab: How to insert zeros in specific places of vector

Can someone help me with the following problem in Matlab? I have a first vector containing the elements values. For example,
[2 8 4 9 3].
And a second one with the desired places in a second vector. For example,
[0 0 1 0 0 0 0 1 1 0 0 1 0 0 1].
Now I want to put the values from the first vector on the positions of the second one to end up with
[0 0 2 0 0 0 0 8 4 0 0 9 0 0 3].
What is the most efficient way of doing this when the size of the vector can be very large. (then thousands of elements)?
You can consider the y values as logical indicators, then use logical indexing to set those values to the values in x.
x = [2 8 4 9 3];
y = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
y(logical(y)) = x;
Alternatively, you could use
y(y==1) = x;
Use self-indexing:
% Your values:
V = [2 8 4 9 3];
% The desired locations of these values:
inds = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
% index the indices and assign
inds(inds>0) = V