I have the following two matrices which are outputs of a procedure. The size of the matrices may change but both matrices will always be the same size: size(TwoHopMat_1) == size(Final_matrix)
Example:
TwoHopMat_1 =
0 0 0 0 1
0 0 1 1 0
0 1 0 1 0
0 1 1 0 0
1 0 0 0 0
Final_matrix =
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 0 0 0
1 0 0 0 1
Now I need to shuffle the final_matrix such that i meet the following conditions after shuffling:
Every column should have a minimum of one 1s
If i have a 1 in a particular position of TwoHopMat_1 then that particular position should not have 1 after shuffling.
The conditions should work even if we give matrices of size 100x100.
first step: set one element of each column of the result matrix ,that is not 1 in Final_matrix ,to 1
second step: then remaining ones randomly inserted into positions of the result matrix that are not 1 in Final_matrix and are not 1 in the first step result
TwoHopMat_1=[...
0 0 0 0 1
0 0 1 1 0
0 1 0 1 0
0 1 1 0 0
1 0 0 0 0];
Final_matrix=[...
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 0 0 0
1 0 0 0 1];
[row col] = size(Final_matrix);
result = zeros(row ,col);
%condition 1 & 2 :
notTwoHop = ~TwoHopMat_1;
s= sum(notTwoHop,1);
c= [0 cumsum(s(1:end - 1))];
f= find(notTwoHop);
r = floor(rand(1, col) .* s) + 1;
i = c + r;
result(f(i)) = 1;
%insert remaining ones randomly into the result
f= find(~(result | TwoHopMat_1));
i = randperm(numel(f), sum(Final_matrix(:))-col);
result(f(i)) =1
A possible solution:
function [result_matrix] = shuffle_matrix(TwoHopMat_1, Final_matrix)
% Condition number 2
ones_mat = ones(size(TwoHopMat_1));
temp_mat = abs(TwoHopMat_1 - ones_mat);
% Condition number 1
ones_to_remove = abs(sum(sum(temp_mat)) - sum(sum(Final_matrix)));
while ones_to_remove > 0
% Random matrix entry
i = floor((size(Final_matrix, 1) * rand())) + 1;
j = floor((size(Final_matrix, 2) * rand())) + 1;
if temp_mat(i,j) == 1
temp_mat(i,j) = 0;
ones_to_remove = ones_to_remove - 1;
end
end
result_matrix = temp_mat;
end
Note: this solution uses brute force.
I need to replace the repeated elements in column of a matrix as 0's and delete the rows which has all 0's. If my matrix is like this means.
Input =
1 0 0 1
0 1 0 1
0 0 1 1
1 1 1 1
My expected output should be like this
Output =
1 0 0 1
0 1 0 0
0 0 1 0
0 0 0 0 ---> this row should be get deleted in this case
This doesn't work for my problem
c = [ 1 1 0 1 0 1 1 1 0 1 1 0];
[c, ic] = unique(a, 'first');
c(~ismember(1:length(a),ic)) = 0;
You can use logical indexing and cumsum:
A = [1 0 0 1;
0 1 0 1;
0 0 1 1;
1 1 1 1];
ind = cumsum(A); %cumulative sum (by column)
A(ind>1) = 0;
A(sum(A')==0,:)=[]
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);
Assume you have an 4x4 matrix A of zeros:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
And an 4x1 vector B that represents column indices for matrix A (so values [1:4])
4
2
3
1
Now I want to increment those columnpositions in matrix A on the index on every row from vector B.
I have tried a couple of constructions myself but can't quite manage to do this.
For example I tried:
A(:, B) = A(:, B)+1
Which just increment every element in A.
This is how I want the operation to act:
>> A(somethting(B)) = A(somethting(B)) + 1
0 0 0 1
0 1 0 0
0 0 1 0
1 0 0 0
You can do this by using the linear index to each of the elements you want to address. Compute this using sub2ind:
>> A = zeros(4)
A =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
>> B = [4 2 3 1]
B =
4 2 3 1
>> i=sub2ind(size(A),B,1:4)
i =
4 6 11 13
>> A(i) = A(i)+1
A =
0 0 0 1
0 1 0 0
0 0 1 0
1 0 0 0
Well just in case you want a looped version :p
A = zeros(4,4);
B = [4, 2, 3, 1];
for i = 1:length(B)
A(i, B(i) ) = A(i, B(i) ) + 1;
end
A = zeros(4);
B = [4 2 3 1];
A(repmat([1:4]',1,4) == repmat(B,4,1)) = 1
A =
0 0 0 1
0 1 0 0
0 0 1 0
1 0 0 0
If I have a matrix:
0 0 3 4
4 3 2 0
2 0 2 0
I want to extract the non-zero elements into some batches, with respect to a rule: if an element is already taken, the other element in the same row/column is not allowed. So the extracted matrix will be:
1st batch:
0 0 3 0
4 0 0 0
0 0 0 0
2nd batch:
0 0 0 4
0 3 0 0
0 0 2 0
3rd batch:
0 0 0 0
0 0 2 0
2 0 0 0
Any other combination of batches is also accepted, as long as all non-zero elements are covered, and the rule is conformed. How would you do that in MATLAB/Octave?
For just the rows, I'd do it as follows:
A = [ 0 0 3 4 ;
4 3 2 0 ;
2 0 2 0 ];
Checking if numbers are nonzero:
Anonzero=A~=0;
>> Anonzero
0 0 1 1
1 1 1 0
1 0 1 0
Take cumsum along the rows of Anonzero:
Aidx=cumsum(A,[],2);
>> Aidx
0 0 1 2
1 2 3 3
1 1 2 2
numbatches=max(Aidx(:,end));
Set indices of zero values back to zero, so they won't get selected
A(~Anonzero)=0;
Extract batches:
batch=cell(numbatches,1);
for ii=1:numbatches
batch{ii}=A.*(Aidx==ii);
end
resulting in:
>>batch{1}
0 0 3 0
4 0 0 0
2 0 0 0
>>batch{2}
0 0 0 4
0 3 0 0
0 0 2 0
>>batch{3}
0 0 0 0
0 0 2 0
0 0 0 0
I assume there can be done something similar for a row and column rule, but I don't see it right away.. I'll think about it ;)
Gunther was already on the right track. You want to select an element, if
the row cumsum of the non-zeros is 1 AND
the column cumsum of the non-zeros is 1 AND
the element itself is non-zero.
The following code solves the problem:
A = [0, 0, 3, 4;
4, 3, 2, 0;
2, 0, 2, 0];
batches = cell(0);
while any(A(:)~=0)
selector = cumsum(A~=0, 1) .* cumsum(A~=0, 2) .* (A~=0) == 1;
batches{end+1} = A .* selector;
A(selector) = 0;
end
Note however that the returned solution is not optimal because its 2nd batch is
0 0 0 4
0 3 0 0
2 0 0 0
which means that the remaining matrix elements are from the same column:
0 0 0 0
0 0 2 0
0 0 2 0
Unfortunately, you cannot draw them in the same batch. So you end up with four batches instead of just three.
Edit: Probably, it is a good idea, to select first those elements, which appear in rows/columns with a lot of non-zeros. For example, one could use these weights
weight = repmat(sum(A~=0, 1), size(A, 1), 1) ...
.* repmat(sum(A~=0, 2), 1, size(A, 2)) .* (A~=0)
weight =
0 0 6 2
6 3 9 0
4 0 6 0
The following algorithm
batches = cell(0);
while any(A(:)~=0)
batch = zeros(size(A));
weight = repmat(sum(A~=0, 1), size(A, 1), 1) ...
.* repmat(sum(A~=0, 2), 1, size(A, 2)) .* (A~=0);
while any(weight(:)~=0)
[r,c] = find(weight == max(weight(:)), 1);
batch(r,c) = A(r,c);
A(r,c) = 0;
weight(r,:) = 0;
weight(:,c) = 0;
end
batches{end+1} = batch;
end
returns those batches.
batches{:}
ans =
0 0 0 4
0 0 2 0
2 0 0 0
ans =
0 0 3 0
4 0 0 0
0 0 0 0
ans =
0 0 0 0
0 3 0 0
0 0 2 0
So it worked at least for this small test case.
An interesting problem no doubt...My guess is that #GuntherStruyf's method will eventually be the one you should select. However, here's a simplistic solution using loops:
A = [
0 0 3 4
4 3 2 0
2 0 2 0 ];
C = {};
nz = A ~= 0;
while any(nz(:))
tmpNz = nz;
tmpA = A;
newNz = false(size(nz));
while true
[i,j] = find(tmpNz, 1);
if isempty(i) || isempty(j), break; end
tmpNz(i,:) = false;
tmpNz(:,j) = false;
newNz(i,j) = true;
end
tmpA(~newNz) = false;
C{end+1} = tmpA;
nz(newNz) = false;
end
This should be quite fast once you get rid of the growing cell-array, e.g., by pre-allocating it with a large number of initial elements, and then removing unused elements afterwards.
Nevertheless, I'd wait until #GuntherStruyf figures his thing out!