Selecting certain zero elements from a matrix in MATLAB - arrays

Suppose I have this matrix:
M =
90 0 40 0
0 0 10 60
55 15 0 10
0 15 5 0
I would like to find all zeroes such that once I select a zero from row i and column j, no more zeroes from row i and column j should be selected. In this example, scanning from left to right and top to bottom, the rows and columns I should get are:
Row Column
1 2
2 1
3 3
4 4
What MATLAB code will produce this for me?

Luis Mendo's answer is correct given the OP's original question of selecting the first zero of each row. However, with our discussion seen in the comments, this requirement has now changed. The understanding (at least from what I gathered from the snippets of code and the requirements) is that once you select a zero at row i and column j, no more zeroes from all of row i and all of column j should be selected. As for loops are usually frowned upon in MATLAB, I saw no other choice but to do this with loops.
My approach was the following:
Find all zeroes in the matrix and find their row and column locations and place each into separate lists.
While we still have a zero to consider:
Place this row and column into a list
Remove all indices from the row list that contain this row in question.
Remove all indices from the column list that contain this column in question
Repeat Step #2 until our row and column location list is empty.
Without further ado, here is the code.
clear all;
close all;
M =[90,0,40,0;0,0,10,60;55,15,0,10;0,15,5,0];
%// Find row and column locations
%// find traverses columns first, so I had to
%// transpose and swap J,I so that it reports
%// row locations first.
[J,I] = find(M.' == 0);
%// List of co-ordinates that meet our criteria
rowCoords = [];
%// While there is still one zero to consider...
while (~isempty(I) && ~isempty(J))
%// Store these for processing
rowToAdd = I(1);
colToAdd = J(1);
%// Add to the list
rowCoords = [rowCoords; [rowToAdd colToAdd]];
%// Remove all row and column co-ordinates
%// that share the same row and column
rowsToRemove = I == rowToAdd | J == colToAdd;
I(rowsToRemove) = [];
J(rowsToRemove) = [];
end
As such, we finally get:
rowCoords =
1 2
2 1
3 3
4 4
It is still unclear on whether the OP wants what Luis Mendo has provided, or what I have interpreted in the comments. The OP verified that how I specified his requirements is what he actually wants but we still do not have any verification. OP: Please verify.

Find the first zero (if any) in each row
[ind1, ind2] = max(M.'==0);
result = [find(ind1); ind2(ind1)].';
In your example, this gives
result =
1 2
2 1
3 3
4 1
Find the first zero (if any) in each row, ignoring columns that have been previously used
M2 = M; %// make a copy of M2. It will be overwritten
[R C] = size(M2);
cols = NaN(R,1); %// initiallize. This will store the result for each row
ind = false(R,1); %// intiallize. This will indicate rows that have a valid zero
for r = 1:R %// for each row
c = find(M2(r,:)==0,1); %// find first valid zero, if any
if ~isempty(c)
cols(r) = c; %// store result
ind(r) = true; %// this row has been found to have a valid zero
M2(:,c) = inf; %// this col can no longer be used
end
end
result = [find(ind) cols(ind)]; %// build result. Only rows with a valid zero
In your example:
result =
1 2
2 1
3 3
4 4

Related

Matlab Array Issues

I have a numerical array CentroidBins which is 3694x4. Columns 3 and 4 are arbitrary X and Y bins with a range of 1-20. My goal in the last bit of code was to go through columns 3 and 4 to count the number of times a particular pair appeared (ie. 1,1 or 1,2....etc) and place that into a 20x20 array with rows being Y bins and columns being X bins. I managed to construct something which looks like what a want, but the output is 18x17, I am assuming it is deleting rows and columns populated by "0". How can I make sure this produces 20x20?
bin20 = centroids_array / 20 %create 20 bins
imRound = round(bin20)
CentroidBins = [centroids_array , imRound]
save("CentroidBins.mat", "CentroidBins");
disp(CentroidBins)
nrow = size(CentroidBins, 1);
B = CentroidBins(:,[3 4]);
NumF = full(sparse(B(1:end-nrow),B(nrow+1:end),1))
to count the occurrence of pairs, you use hist and unique
a=[1 2; 1 2; 2 3; 8 1; 2 3];
[foo,ix,jx]=unique(a,'rows');
count=hist(jx,unique(jx)) % report the repeated counts of each unique pair
foo % lists the unique pairs

How to check if all the entries in columns of a matrix are equal (in MATLAB)?

I have a matrix of growing length for example a 4-by-x matrix A where x is increasing in a loop. I want to find the smallest column c where all columns before that, each, carry one single number. The matrix A can look like:
A = [1 2 3 4;
1 2 3 5;
1 2 3 1;
1 2 3 0];
where c=3, and x=4.
At each iteration of the loop where A grows in length, the value of index c grows as well. Therefore, at each iteration, I want to update the value of c. How efficiently can I code this in Matlab?
Let's say you had the matrix A and you wanted to check a particular column iito see if all its elements are the same. The code would be:
all(A(:, ii)==A(1, ii)) % checks if all elements in column are same as first element
Also, keep in mind that once the condition is broken, x cannot be updated anymore. Therefore, your code should be:
x = 0;
while true
%% expand A by one column
if ~all(A(:, x)==A(1, x)) % true if all elements in column are not the same as first element
break;
end
x = x+1;
end
You could use this:
c = find(arrayfun(#(ind)all(A(1, ind)==A(:, ind)), 1:x), 1, 'first');
This finds the first column where not all values are the same. If you run this in a loop, you can detect when entries in a column start to differ:
for x = 1:maxX
% grow A
c = find(arrayfun(#(ind)~all(A(1, ind)==A(:, ind)), 1:x), 1, 'first');
% If c is empty, all columns have values equal to first row.
% Otherwise, we have to subtract 1 to get the number of columns with equal values
if isempty(c)
c = x;
else
c = c - 1;
end
end
Let me give a try as well:
% Find the columns which's elements are same and sum the logical array up
c = sum(A(1,:) == power(prod(A,1), 1/size(A,1)))
d=size(A,2)
To find the last column such that each column up to that one consists of equal values:
c = find(any(diff(A,1,1),1),1)-1;
or
c = find(any(bsxfun(#ne, A, A(1,:)),1),1)-1;
For example:
>> A = [1 2 3 4 5 6;
1 2 3 5 5 7;
1 2 3 1 5 0;
1 2 3 0 5 8];
>> c = find(any(diff(A,1,1),1),1)-1
c =
3
You can try this (easy and fast):
Equal_test = A(1,:)==A(2,:)& A(2,:)==A(3,:)&A(3,:)==A(4,:);
c=find(Equal_test==false,1,'first')-1;
You can also check the result of find if you want.

remove the rows in a matrix whose elements are the same in matlab

Given a 2-column matrix, for instance. The input is:
[ 1,2;
3,4;
5,5]
The expected output is:
[1,2;
3,4;]
Does anyone know how do accomplish this? Many thanks for your time and attention.
You could use logical indexing:
A = [1 2;3 4;5 5];
match = A(:,1) == A(:,2); // 1 where row has the same elements in both columns
A(match,:) = []; // make the match columns empty
You would need to make this more generic for another case, but for two columns and your example this will work.
Your question suggests your matrix may have an arbitrary number of columns. In that case you may want to delete a row if it has (a) any two elements equal, or (b) all elements equal.
One possible approach is:
Apply sort along each row;
Use diff to compute differences between consecutive elements;
Generate a logical index with all to (a) keep rows for which all such differences are non-zero, or with any to (b) keep rows for which any such difference is non-zero:
So:
X = [1 2 3;
3 4 3;
5 5 5];
Y = X(all(diff(sort(X,2),[],2),2),:);
Z = X(any(diff(sort(X,2),[],2),2),:);
gives
Y =
1 2 3
Z =
1 2 3
3 4 3

How to build a binary matrix from sums

I have two decimal number variables, colSum and rowSum, using those I want to build a matrix of binary values based on those sums, the rowSum array variable is the result of adding all the 1's for each row, the same goes for colSum array.
So ,if you have
rowSum = [0,1,2]
colSum = [1,1,1]
you will have to build properly the following array
matrix = [
[0,0,0],
[0,0,1],
[1,1,0]
]
I'm using this method in PHP, that works for a 3x3 matrix, but not for a bigger one, like 8x8.
First ,fill all the 1's in the rows using the rowSum value.
Then ,try to find a wrong sum value of 2 columns, with a pivot I inter-change them (1 with a cero value) in the same row, until i get the correct value of colSum.
But it will not work because I need some control of the criteria to change the 1 and 0 in the same row for two columns...
This is the method I'm using.
Let's say we have this Matrix (N=3 -> NxN):
0 0 0
0 0 1
1 1 0
then we have the following arrays
R0 = {0,1,2} //--> result of sums of each rows: ( 0+0+0, 0+0+1 , 1+1+0 )
C0 = {1,1,1} // ->sums of each columns
Step 1
Create and fill a NxN array using as many 1's as R0(i) in each row:
0 0 0
1 0 0
1 1 0
compute sums of this new matrix now:
R1 = {0,1,2}
C1 = {2,1,0}
Step 2
Check if for all the elements of the column sums of the created matrix has the same value as C0 (origin)
for ( i=0, N-1) do
if C0(i)!=C1(i) then
ReplaceColumn(i)
end
end
To replace a column we have to dig inside the conditions.
C0(0) = 1 != C1(0) = 2
the first column sum does meet the condition to call the replace ,so
Step 3
Choose criteria for apply the branch & bound method and find the best row to change column that satisfy the global condition (all column sums).
The amount of changes for a difference between columns sums is:
|C0(i)-C1(i)|
for this example, |C0(0)-C1(0)| = 1 change.
Go back condition must be if the change generates a greater difference between the total sum of columns.
Σi,N(|C0(i)-C1(i)|)
So, could this method really work?
Is the goal to construct the matrix that satisfies the row and column sums or a matrix that satisfies them? It's not clear from the question, but if it's the former ("the" case) then it's not going to possible.
Suppose it were the case that you could uniquely represent any m × m matrix of bits in this way. Then consider the following hypothetical compression algorithm.
Take 22n bits of data
Treat it as 2n × 2n bits
To describe the data, use 2 × 2n row and column sums, each using at most log2(2n) = n bits
The data is compressed to 2 × n × 2n bits
Since 2 × n × 2n << 22n and this process could just keep being repeated, the supposition that you can uniquely represent any m × m matrix of bits by only its row and column sums is false.

Sort cell array base on the 2D value

I have a 3X3 cell array and each element store a (x,y) point.
The point are generate by random number from [0,1].
What I want to do is sort the cell array so that it looks like following
ex: 9 points
each circle is one 2D point
index:(1,1) in the left top corner and (3,3) to the right bottom corner as the usual array index
that is to ensure the topological order.
How do I do it?
Thank in advance.
for the example
pairs = [4 9 2 6 5 1 7 8 3; 9 6 2 1 3 8 7 4 5] (row 1 = x-values, row 2 = y-values))
what I want to do is put them in the cell array so that they can be connected by read lines like the image's topology.
The number of permutations is factorial(9), which is not terribly large. So a brute-froce approach is feasible: test all permutations for your desired conditions, and pick the first that is valid.
In the following I'm using a 2x3x3 array, instead of a 3x3 cell array containing length-2 vectors, because it's much easier that way.
N = 3;
data = rand(2,N,N);
permutations = perms(1:N^2); %// generate all permutations
for k = 1:numel(permutations)
dx = reshape(data(1,permutations(k,:)),N,N); %// permuted x data
dy = reshape(data(2,permutations(k,:)),N,N); %// permuted y data
if all(all(diff(dy,[],1)<0)) && all(all(diff(dx,[],2)>0)) %// solution found
disp(dx) %// display solution: x values
disp(dy) %// y values
break %// we only want one solution
end
end
Note that for some choices of data there may not be a solution.

Resources