Putting 1's in certain places - matlab

I have 2 matrices
Matrix A = [7 3 5 2 8 4 1 6 9;
5 2 6 1 4 3 9 7 8;
9 1 4 5 2 6 3 6 7;
4 8 1 6 3 7 2 9 5;
6 1 7 2 8 4 5 9 3]
Matrix B = [1 0 0 0 0 0 0 0 0;
0 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 0;
0 0 0 1 0 1 0 0 0;
0 0 0 0 0 0 0 0 1]
Matrix A and B are already defined.
Here each column can't have more than 1 what i want to do is that if when i do sum for Matrix B if i found 0 in it i have to add 1's in the places of the zero's but in certain places. In each row the 1's have to be placed in certain groups. For example if a 1 is placed in column 1, then it can be placed as well in column 2 or 3 only. It can't be placed anywhere else. If in another row it is placed in column 5, then it can be placed in column 4 or 6 only and so on. It's like group of 3. Each 3 columns are together.
To be more clear:
Here the sum of matrix B is [1 1 1 1 0 1 0 1 1]. The zeros here are placed in column 5 and 7 and i want to add 1 putting in mind where the 1 is going to be placed in the matrix. So in this example the 1 of column 5 can only be placed in row 4 as the 1's in this row are placed in column 4 and 6. The 1 of column 7 can be placed in row 5 or row 3. If we have choice between 2 rows then the 1 will be placed in the placed of the higher number of Matrix A.
The 1's have to be placed in groups; columns 1, 2 and 3 are together, columns 4,5 and 6 are together and columns 7, 8 and 9 are together. so if the 1 is placed in 1 column of the group then it can't be placed in any other place.
Let me simplify it if we have an array like this [0 0 0 0 0 0 0 1 1] This array has 3 categories, columns 1,2 and 3 are 1st category, columns 4,5 and 6 are 2nd category and so on. here i want to place a 1 so that the 3rd category won't have a zero element. This is what i want to do briefly but with a whole matrix with all the categories.
so here the output will be =
[1 0 0 0 0 0 0 0 0;
0 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 0;
0 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 1 0 1]
This code was tried but it doesn't give the required output as the 1 was placed in the 1st row not in the place where it has to be (the category that it should be in).
sum_cols_B = sum(B); % Sum of Matrix B (dim 1)
[~, idx] = find(sum_cols_B == 0); % Get indices where sum == 0
% Using loop to go through the indices (where sum = 0)
for ii = idx
B(1,ii) = 1; % Insert 1 in the first position of that
end % column in Matrix B
Ask me if the question is still not clear.!

Here's an updated loop that will add the missing 1's:
sum_cols_B = sum(B);
[~, idx] = find(sum_cols_B == 0);
group_size = 3;
for ii = idx
% Calculate the starting column of the group for column ii
% There are (ii-1)/group_size groups
% Add 1 for 1-based indexing
group_start = floor((ii-1)/group_size)*group_size + 1;
% Determine which rows in the current group have nonzero values
group_mask = sum(B(:,group_start:group_start+group_size-1), 2) > 0;
% Find the row number of the max in A column ii corresponding to mask
[~,rownum] = max(A(:,ii).*group_mask);
% The value in column ii of B should have a 1 inserted
% at the row containing the max in A
B(rownum,ii) = 1;
end
Results for B above are:
B =
1 0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0
0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 1 0 1

B = [1 0 0 0 0 0 0 0 0;...
0 1 1 0 0 0 0 0 0;...
0 0 0 0 0 0 0 1 0;...
0 0 0 1 0 1 0 0 0;...
0 0 0 0 0 0 0 0 1]; % Matrix - using this as an example
sum_cols_B = sum(B); % Sum of Matrix B (dim 1)
[~, idx] = find(sum_cols_B == 0); % Get indices where sum == 0
% Using loop to go through the indices (where sum = 0)
for ii = idx
B(1,ii) = 1; % Insert 1 in the first position of that
end % column in Matrix B

Related

insert a row and a line in a matrix

I create a matrix b from a matrix a in the following way:
a=[1 2 ; 3 4];
b= [a zeros(2); zeros(2) a]
b =
1 2 0 0
3 4 0 0
0 0 1 2
0 0 3 4
Successively, I want to insert a line and a column of zeros at a certain point of the matrix. Let's say at middle way:
idx=2;
c=[b(1:idx,:); zeros(1,4); b(idx+1:end,:)]
c =
1 2 0 0
3 4 0 0
0 0 0 0
0 0 1 2
0 0 3 4
c=[c(:,1:idx) zeros(5,1) c(:,idx+1:end)]
c =
1 2 0 0 0
3 4 0 0 0
0 0 0 0 0
0 0 0 1 2
0 0 0 3 4
Is there a more intelligent way of doing this?
Here is another way(I don't know if it is a more intelligent way).
Assuming that you have the row index as row and the column index as col:
sc = size(b) + 1;
c = zeros(sc);
ROW = true(sc(1), 1);
ROW(row) = false;
COL = true(1, sc(2));
COL(col) = false;
Then in MATLAB r2016b /Octave you can write
c(ROW & COL)=b;
In pre 2016b you can use bsxfun
c(bsxfun(#and, ROW , COL))=b;

Create N copies of a vector based on number of nonzero values in that vector

I have a 64-by-1 vector which contains 27 non-zero values. I want to create N copies from that vector such that each copy contains only 4 non-zero values (in that case the first 6 copies will have 4 non-zero values and the last copy will contain only 3 non-zero values) using MATLAB.
For example:
orig_vector = [0 0 0 0 1 0 0 0 0 5 0 0 0 2 0 1 0 2 3 1 1 ];
first_copy = [0 0 0 0 1 0 0 0 0 5 0 0 0 2 0 1 0 0 0 0 0 ];
second_copy = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 1 ];
How can this be done?
Perhaps something like:
non_zero_indices = find(orig_vector); % get array indices of non-zero elements
n_non_zero = length(non_zero_indices);
n_copies = ceil(n_non_zero / 4); % eg. with 6 non-zero elements we will have 2 copies
new_vectors = zeros(n_copies, length(orig_vector)); % matrix of new vectors where vectors go in rows
for i=0:n_copies - 2
idx = non_zero_indices(1+i*4:4+i*4);
new_vectors(i+1, idx) = orig_vector(idx);
end
idx = non_zero_indices(1+(n_copies-1)*4:end); % handle end which may have fewer than 4 elements
new_vectors(n_copies, idx) = orig_vector(idx);

Matrix of 0s and 1s Where Assignment in Subsequent Rows are Contingent on the Previous Row

I'd like to create a Matrix in MATLAB where:
The First row consists of a random arrangement of 0s and 1s, split evenly (i.e. 50-50).
The Second row randomly assigns zeros to 50% of the 0s and 1s in the first row, and ones to the remaining 50%.
The Third row randomly assigns zeros to 50% of the 0s and 1s in the second row, and ones to the remaining 50%.
Non-randomized Example:
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
Any suggestions?
A solution based on checking whether numbers are bigger or smaller than the median. As long as the number of columns tested is even, exactly half of a set of random doubles will be bigger than the median, and half will be smaller. This guarantees that there's exactly 50% of bits get flipped.
nRows = 3;
nCols = 16; %# divisible by 4
%# seed the array
%# assume that the numbers in each row are unique (very, very likely)
array = rand(nRows,nCols);
out = false(nRows,nCols);
%# first row is special
out(1,:) = array(1,:) > median(array(1,:));
%# for the rest of the row, check median for the zeros/ones in the previous row
for iRow = 2:nRows
zeroIdx = out(iRow-1,:) == 0;
%# > or < do not matter, both will replace zeros/ones
%# and replace with exactly half zeros and half ones
out(iRow,zeroIdx) = array(iRow,zeroIdx) > median(array(iRow,zeroIdx));
out(iRow,~zeroIdx) = array(iRow,~zeroIdx) > median(array(iRow,~zeroIdx));
end
I'd offer a short bsxfun solution:
%// number of divisions
n = 4;
%// unshuffled matrix like in your example
unshuffled = bsxfun(#(a,b) mod(a,2*b) > b-1, meshgrid(1:n^2,1:n) - 1, (2.^((n-1):-1:0)).') %'
%// shuffle columns
shuffled = unshuffled(:,randperm(n^2))
unshuffled =
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
shuffled =
1 0 1 1 0 1 0 1 1 1 1 0 0 0 0 0
1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 1 1 0 1 1 0 1 1
1 1 1 1 0 0 0 0 0 0 1 0 0 1 1 1
First you need to create the unshuffled matrix, which can be done by comparing the matrix generated by meshgrid(1:n^2,1:n) with a row dependent modulus. Finally you just need to shuffle the columns.
If you have the Statistics Toolbox, you can do it very easily with randsample:
M = 3; %// number of rows
N = 16; %// number of columns. Should be multiple of 4, according to problem definition
result = zeros(M,N); %// preallocate and initiallize to zeros
result(1, randsample(1:N,N/2)) = 1; %// first row: half values set to one, half to zero
for m = 2:M
result(m, :) = result(m-1, :); %// initiallize row m equal to row m-1
result(m, randsample(find(result(m-1,:)), N/4)) = 0; %// change half of ones
result(m, randsample(find(~result(m-1,:)), N/4)) = 1; %// change half of zeros
end
Example result:
result =
0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1
1 1 0 0 0 1 1 1 0 1 0 1 0 0 0 1
1 0 0 0 1 0 0 1 0 1 1 0 1 1 0 1
A solution using randperm:
nrows = 3;
ncols = 16;
M = zeros(nrows,ncols);
%// seed the first row
M(1,1:ncols/2) = 1;
M(1,:) = M(1,randperm(ncols));
for r = 2:nrows
%// Find ncols/4 random between 1 and ncols/2. These will be used to index half of the previous rows 1 elements and set them to one
idx = randperm(ncols/2);
idx1 = idx(1:ncols/4);
%// Do the same thing again, but this time it will be used for the 0 elements of the previous row
idx = randperm(ncols/2);
idx0 = idx(1:ncols/4);
idx_prev1 = find(M(r-1,:)); %// Find where the 1 elements were in the last row
idx_prev0 = find(~M(r-1,:)); %// Find where the 0 elements were in the last row
M(r,idx_prev1(idx1))=1; %// Set half of the previous rows 1 elements in this row to 1
M(r,idx_prev0(idx0))=1; %// Set half of the previous rows 0 elements in this row to 1
end

Linear span of a vector in MATLAB

I'm looking for a way to generate the spans of a given vector in MATLAB.
For example:
if a = [ 0 1 0 1] I need all vectors of the form [0 x 0 y], 1 <= x <= max1, 1 <= y <= max2,.
or if
a = [ 0 1 0 1 1 0] I need all vectors of the form [0 x 0 y z 0], 1 <= x <= max1, 1 <= y <= max2, 1<= z <= max3.
Note that the vector can have a variable number of 1's.
My first impression is that I would need a variable number of for loops, though I don't know if that is doable in MATLAB. Also any other ideas are welcome!
You don't need multiple for loops for this. The code below generates all required vectors as rows of a tall matrix. It actually creates the columns of the matrix one at a time. Each column will have numbers 1:m(i) arranged in the pattern where
each term repeats the number of times equal to the product of all m-numbers after m(i)
the whole pattern repeats the number of times equal to the product of all m-numbers before m(i)
This is what repmat(kron(1:m(i),ones(1,after)),1,before)' does. (Starting with R2015a you can use repelem to simplify this by replacing the kron command, but I don't have that release yet.)
a = [0 1 0 1 1 0];
m = [2 4 3]; // the numbers max1, max2, max3
A = zeros(prod(m), length(a));
i = 1; // runs through elements of m
for j=1:length(a) // runs through elements of a
if (a(j)>0)
before = prod(m(1:i-1));
after = prod(m(i+1:end));
A(:,j) = repmat(kron(1:m(i),ones(1,after)),1,before)';
i = i+1;
end
end
Output:
0 1 0 1 1 0
0 1 0 1 2 0
0 1 0 1 3 0
0 1 0 2 1 0
0 1 0 2 2 0
0 1 0 2 3 0
0 1 0 3 1 0
0 1 0 3 2 0
0 1 0 3 3 0
0 1 0 4 1 0
0 1 0 4 2 0
0 1 0 4 3 0
0 2 0 1 1 0
0 2 0 1 2 0
0 2 0 1 3 0
0 2 0 2 1 0
0 2 0 2 2 0
0 2 0 2 3 0
0 2 0 3 1 0
0 2 0 3 2 0
0 2 0 3 3 0
0 2 0 4 1 0
0 2 0 4 2 0
0 2 0 4 3 0

Assign values w/ multiple conditions

Let's have a M = [10 x 4 x 12] matrix. As example I take the M(:,:,4):
val(:,:,4) =
0 0 1 0
0 1 1 1
0 0 0 1
1 1 1 1
1 1 0 1
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
How can I obtain this:
val(:,:,4) =
0 0 3 0
0 2 2 2
0 0 0 4
1 1 1 1
1 1 0 1
0 2 2 2
1 1 1 1
1 1 1 1
0 0 3 3
0 0 3 3
If I have 1 in the first column then all the subsequent 1's should be 1.
If I have 0 in the first column but 1 in the second, all the subsequent 1's should be 2.
If I have 0 in the first and second column but 1 in the third then all the subsequent 1's should be 3.
If I have 0 in the first 3 columns but 1 in the forth then this one should be four.
Note: The logical matrix M is constructed:
Tab = [reshape(Avg_1step.',10,1,[]) reshape(Avg_2step.',10,1,[]) ...
reshape(Avg_4step.',10,1,[]) reshape(Avg_6step.',10,1,[])];
M = Tab>=repmat([20 40 60 80],10,1,size(Tab,3));
This is a very simple approach that works for both 2D and 3D matrices.
%// Find the column index of the first element in each "slice".
[~, idx] = max(val,[],2);
%// Multiply the column index with each row of the initial matrix
bsxfun(#times, val, idx);
This could be one approach -
%// Concatenate input array along dim3 to create a 2D array for easy work ahead
M2d = reshape(permute(M,[1 3 2]),size(M,1)*size(M,3),[]);
%// Find matches for each case, index into each matching row and
%// elementwise multiply all elements with the corresponding multiplying
%// factor of 2 or 3 or 4 and thus obtain the desired output but as 2D array
%// NOTE: Case 1 would not change any value, so it was skipped.
case2m = all(bsxfun(#eq,M2d(:,1:2),[0 1]),2);
M2d(case2m,:) = bsxfun(#times,M2d(case2m,:),2);
case3m = all(bsxfun(#eq,M2d(:,1:3),[0 0 1]),2);
M2d(case3m,:) = bsxfun(#times,M2d(case3m,:),3);
case4m = all(bsxfun(#eq,M2d(:,1:4),[0 0 0 1]),2);
M2d(case4m,:) = bsxfun(#times,M2d(case4m,:),4);
%// Cut the 2D array thus obtained at every size(a,1) to give us back a 3D
%// array version of the expected values
Mout = permute(reshape(M2d,size(M,1),size(M,3),[]),[1 3 2])
Code run with a random 6 x 4 x 2 sized input array -
M(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 1 1
1 0 0 0
1 0 1 1
M(:,:,2) =
0 1 0 1
1 1 0 0
1 1 0 0
0 0 1 1
0 0 0 1
0 0 1 0
Mout(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 3 3
1 0 0 0
1 0 1 1
Mout(:,:,2) =
0 2 0 2
1 1 0 0
1 1 0 0
0 0 3 3
0 0 0 4
0 0 3 0