Vector to matrix with row sum 1 - matlab

I have a logical 1-by-n vector with sum m. Now, I need to convert it into a matrix m-by-n in a way that the row sum is equal 1.
vector (1-by-8) with sum 4
[0 1 0 0 1 0 1 1]
matrix (4-by-8) with row sum 1
[0 1 0 0 0 0 0 0;
0 0 0 0 1 0 0 0;
0 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 1]
Is there a mathematically efficient way without calculating the sum, creating a empty matrix, loop through the vector and adding the 1s row by row?

I think that in that case, given your input, you don't even need to calculate the sum.
You can define an identity matrix of size n, then use your input vector to sample the required rows out of it:
I = eye(n);
y = I(x, :) ; % Output Matrix. x is the input vector

Here's another method, using sparse:
matrix = full(sparse(1:m, find(vector), 1, m, n));

Related

How to generate a vector that orthogonal to other vectors?

I have a matrix A which is
A=[1 0 0 1 0;
0 1 1 0 0;
0 0 1 1 0;
1 1 1 0 0]
And a given vector v=[ 0 0 1 1 0] which has two elements one. I have to change the position of element one such that the new vector v is orthogonal to all the rows in the matrix A.
How can I do it in Matlab?
To verify the correct answer, just check gfrank([A;v_new]) is 5 (i.e v_new=[0 1 0 0 1]).
Note that: Two vectors uand v whose dot product is u.v=0 (i.e., the vectors are perpendicular) are said to be orthogonal.
As AVK also mentioned in the comments, v_new = [0 1 0 0 1] is not orthogonal to all rows of A.
Explanation:-
A=[1 0 0 1 0;
0 1 1 0 0;
0 0 1 1 0;
1 1 1 0 0]
For A(1,:).*v = 0 to A(4,:).*v = 0,
0 x x 0 x % elements of v so that it's orthagonal to the 1st row of A
x 0 0 x x % -------------------------------------------- 2nd row of A
x x 0 0 x % -------------------------------------------- 3rd row of A
0 0 0 x x % -------------------------------------------- 4th row of A
where 0 represents the terms which have to be 0 and x represents the terms which can be either 0 or 1.
If you look as a whole, first 4 columns of v have to be zero so that the output is orthagonal to all rows of A. The 5th column can either be zero or 1.
So,
v_new can either be: v_new = [0 0 0 0 1] or v_new = [0 0 0 0 0]
From above explanation, you can also see that [0 1 0 0 1] is not orthagonal to 2nd and 4th row of A
Solution:-
To find v_new, you can use null function as: v_new = null(A).'
which gives: v_new = [0 0 0 0 1] for which gfrank([A;v_new]) also gives 5.
Maybe this will help you see the orthogonality between two vectors in N dimension.
N=100;
B1 = ones(1,N);
B2 = -1*ones(1,N/2);
B2 = [ones(1,N/2) B2];
B2 = transpose(B2);
B3 = dot(B1,B2);
The above code generates two vectors in N dimension. To check for orthogonality just transpose one of the vectors and multiply with the other one. You should get zero if they are Orthogonal.
The example I used makes sure that I get zero indeed.

return the index of the last K non-zero element of each row of a matrix

Is there a vectorization way of returning the index of the last K nonzero elements of each row of a matrix?
For example, my matrix only contains 0 and 1 and the last column of each row is always 1. Then I want to find the index of the last K, where K>1, nonzero elements of each row. If a row only has M (less than K) nonzero elements, then the index for that row is just the index of the last M nonzero element. e.g.
A = [0 1 0 1;
1 1 0 1;
1 1 1 1;
0 0 0 1]
And my K = 2, then I expected to return a matrix such that
B = [0 1 0 1;
0 1 0 1;
0 0 1 1;
0 0 0 1]
Namely B is originally a zero matrix with same shape as A, then it copies each row of A where the corresponding column starts from the index of the last K non-zero element of the row of A (and if in one row of A there is only M < K non-zero element, then it starts from the index of the last M non-zero element of that row of A)
Knowing that elements are only 0 or 1, you can make a mask using cumsum on the flipped matrix A and throw away values with a cumulative sum greater than k:
A = [0 1 0 1;1 1 0 1;1 1 1 1;0 0 0 1]
k = 2;
C = fliplr(cumsum(fliplr(A), 2)); % take the cumulative sum backwards across rows
M = (C <= k); % cumsum <= k includes 0 elements too, so...
B = A .* M % multiply original matrix by mask
As mentioned in the comments (Thanks #KQS!), if you're using a recent version of MATLAB, there's a direction optional parameter to cumsum, so the line to generate C can be shortened to:
C = cumsum(A, 2, 'reverse');
Results:
A =
0 1 0 1
1 1 0 1
1 1 1 1
0 0 0 1
B =
0 1 0 1
0 1 0 1
0 0 1 1
0 0 0 1
knowing that find function can get indices of last k elements, we can use bsxfun to apply find to rows of a matrix to find which element in each row satisfy the condition. find again used to extract rows and columns of nonzero elements of the resultant matrix, so reducing size of data and complexity of operations. then save the result to a sparse matrix then convert to full matrix:
A = [0 1 0 1;
1 1 0 1;
1 1 1 1;
0 0 0 1]
k = 2;
[row , col]= size(A);
last_nz = bsxfun(#(a,b)find(a,b,'last'),A',(repmat(k, 1, row))); %get indices of last two nonzero elements for each row
[~,rr,cc]=find(last_nz); %get columns and rows of correspondong element for whole matrix
B = full(sparse(rr,cc,1));

Trim Binary Matrix in MatLab

I have a binary matrix like this:
0 0 0 0 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 1 0 1 0
0 0 0 1 0 0
0 0 0 0 0 0
and I want to trim this matrix (in other words, remove zeroes at the boundaries) to be like:
0 0 1 0
1 0 0 0
0 1 0 1
0 0 1 0
How to do this the "Matlab" way? that's not to use conventional loops and conditions.
To be clearer, the matrix should be reduced to start from the first column which has at least one 1, and ends at the last column with the same condition, inclusive. Any column out of this range should be removed. Same rules apply for rows.
Thanks.
If you have the data in matrix M...
x = find(any(M,2),1,'first'):find(any(M,2),1,'last');
y = find(any(M),1,'first'):find(any(M),1,'last');
M(x, y)
Or, if you know that there will be a 1 in every row/col except the edges:
M(any(M,2), any(M))
Extension to higher dimensions:
Assuming a 3D matrix to be trimmed, this is more straightforward:
M=rand(3,3,3); % generating a random 3D matrix
M(2,:,:)=0; % just to make a check if it works in extreme case of having zeros in the middle
padded = padarray(M,[2 2 2]); % making some zero boundaries
[r,c,v]=ind2sub(size(padded),find(padded));
recoveredM=padded(min(r):max(r),min(c):max(c),min(v):max(v));
check=M==recoveredM % checking to see if M is successfully recovered
You could use the fact that find can return row and column indices:
[r1, c1] = find(x, 1, 'first')
[r2, c2] = find(x, 1, 'last')
x(r1:r2, c1:c2)

Creating an m by n matrix of 0s and 1s from m-sized vector of column indexes

I have a m-dimensional vector of integers ranging from 1 to n. These integers are column indexes for m × n matrix.
I want to create a m × n matrix of 0s and 1s, where in m-th row there's a 1 in the column that is specified by m-th value in my vector.
Example:
% my vector (3-dimensional, values from 1 to 4):
v = [4;
1;
2];
% corresponding 3 × 4 matrix
M = [0 0 0 1;
1 0 0 0;
0 1 0 0];
Is this possible without a for-loop?
Of course, that's why they invented sparse matrices:
>> M = sparse(1:length(v),v,ones(length(v),1))
M =
(2,1) 1
(3,2) 1
(1,4) 1
which you can convert to a full matrix if you want with full:
>> full(M)
ans =
0 0 0 1
1 0 0 0
0 1 0 0
Or without sparse matrix:
>> M = zeros(max(v),length(v));
>> M(v'+[0:size(M,2)-1]*size(M,1)) = 1;
>> M = M'
M =
0 0 0 1
1 0 0 0
0 1 0 0
Transposition is used because in matlab arrays are addressed by columns
In Octave, at least as of 3.6.3, you can do this easily using broadcasting:
M = v==1:4

How can I rearrange the columns of this matrix?

Given a binary matrix in which every row and column contains exactly only one 1, I need to rearrange the matrix columnwise so that it will become an identity matrix. For example, given a binary matrix:
Binary = [ 0 1 0 0 0
0 0 1 0 0
1 0 0 0 0
0 0 0 0 1
0 0 0 1 0 ]
To get the identity matrix we rearrange the column as 2 3 1 5 4.
How can we optimally rearrange the columns for any given arbitrary square binary matrix?
A very simple way to do this is to use the function FIND like so:
[index,~] = find(Binary.'); %'# Transpose the matrix and find the row indices
%# of the non-zero entries
And you can test that it work as follows:
>> Binary(:,index)
ans =
1 0 0 0 0 %# Yup, that's an identity matrix alright!
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
OLD APPROACH:
This isn't as compact or efficient as the above solution, but you could also transpose the matrix and use SORTROWS to sort the columns (now transposed into the rows) and return the sort indices. This will actually sort values in ascending order, which will give you an anti-diagonal matrix, so you will want to flip the vector of indices using FLIPUD. Here's the code:
[~,index] = sortrows(Binary.'); %'# Transpose and sort the matrix
index = flipud(index); %# Flip the index vector
If you know the matrix can be manipulated into an identity matrix, why don't you just create an identity matrix with the same dimensions?
identity_matrix=eye(length(Binary))