4
votes

In MATLAB, say I have a set of square matrices, say A, with trace(A)=0 as follows:

For example,

A = [0 1 2; 3 0 4; 5 6 0] 

How can I remove the zeros and then vertically collapse the matrix to become as follow:

A_reduced = [1 2; 3 4; 5 6]

More generally, what if the zeroes can appear anywhere in the column (i.e., not necessarily at the long diagonal)? Assuming, of course, that the total number of zeros for all columns are the same.

The matrix can be quite big (hundreds x hundreds in dimension). So, an efficient way will be appreciated.

6
Tried this before. This doesn't maintain the matrix structure - I'm referring to the "vertically collapsing the matrix" part. - Val K
Sorry. I think I have confused a lot of you when I used A' in my original post. I meant to indicate a changed / reduced A, not A transposed. I've now changed A' to A_reduced. - Val K
Shouldn't number of zeros in each row to be the same, rather than number of zeros in each column as stated in the question, to enable vertical collapsing? Something like this - A = [0 3 0 2; 3 0 0 1; 7 0 6 0; 1 0 6 0;0 16 0 9]? - Divakar
Could you use a more random sample with "total number of zeros for all columns are the same" condition and state the desired output? For example something like this has two zeros in every column - A = [0 3 7 1 0;3 0 0 0 6; 0 0 6 5 0;3 2 0 0 6], so what must be the expected output for this case? - Divakar
Your example A_reduced assumes the number of zeros in all rows is the same, and then can you compress horizontally. So your question is confusing. Anyway, I think my answer convers the two possibilities - Luis Mendo

6 Answers

4
votes
  • To compress the matrix vertically (assuming every column has the same number of zeros):

    A_reduced_v = reshape(nonzeros(A), nnz(A(:,1)), []);
    
  • To compress the matrix horizontally (assuming every row has the same number of zeros):

    A_reduced_h = reshape(nonzeros(A.'), nnz(A(1,:)), []).';
    
3
votes

Case #1

Assuming that A has equal number of zeros across all rows, you can compress it horizontally (i.e. per row) with this -

At = A' %//'# transpose input array
out = reshape(At(At~=0),size(A,2)-sum(A(1,:)==0),[]).' %//'# final output

Sample code run -

>> A
A =
     0     3     0     2
     3     0     0     1
     7     0     6     0
     1     0     6     0
     0    16     0     9
>> out
out =
     3     2
     3     1
     7     6
     1     6
    16     9

Case #2

If A has equal number of zeros across all columns, you can compress it vertically (i.e. per column) with something like this -

out = reshape(A(A~=0),size(A,1)-sum(A(:,1)==0),[])  %//'# final output

Sample code run -

>> A
A =
     0     3     7     1     0
     3     0     0     0    16
     0     0     6     6     0
     2     1     0     0     9
>> out
out =
     3     3     7     1    16
     2     1     6     6     9
2
votes

This seems to work, quite fiddly to get the behaviour right with transposing:

>> B = A';
>> C = B(:);
>> reshape(C(~C==0), size(A) - [1, 0])'

ans =

     1     2
     3     4
     5     6
1
votes

As your zeros are always in the main diagonal you can do the following:

l = tril(A, -1);
u = triu(A,  1);
out = l(:, 1:end-1) + u(:, 2:end)
0
votes

A correct and very simple way to do what you want is:

A = [0 1 2; 3 0 4; 5 6 0]

A =

 0     1     2
 3     0     4
 5     6     0

A = sort((A(find(A))))

A =

 1
 2
 3
 4
 5
 6

A = reshape(A, 2, 3)

A =

 1     3     5
 2     4     6
0
votes

I came up with almost the same solution as Mr E's though with another reshape command. This solution is more universal, as it uses the number of rows in A to create the final matrix, instead of counting the number of zeros or assuming a fixed number of zeros..

B = A.';
B = B(:);
C = reshape(B(B~=0),[],size(A,1)).'