Algorithm to get the entries of a table? - arrays

Say I have this table of non-negative entries:
1 2 3 sum
1 4 5 1 10
2 6 12 7 25
3 0 3 14 17
4 7 2 5 14
sum 17 22 27 66
given:
the number of columns C and number of rows R
the two sums entries (the sum of each row and the sum of each column)
and the total (66 in this example)
The goal is to produce the entries of the table (the inner cells; not the same ones. but, the sum must be equal to the given ones for each row and each column)
all entries must be positive values.
Any pseudo code to do it?

Iterate through the table cells in any order you like. At each step put the largest number there that is still allowed by the two sum constraints.
For example if we go row by row:
10 0 0
7 18 0
0 4 13
0 0 14

Try my pseudo code. This rule named something like "Rule of North-West corner" (I unable find real name of this rule on wiki)
row = 1
col = 1
while (col <= C && row <= R)
Matrix[col, row] = Min(colsum[col], rowsum[row])
colsum[col] = colsum[col] - Matrix[col, row]
rowsum[row] = rowsum[row] - Matrix[col, row]
while (col <= C && colsum[col] == 0) col++
while (row <= R && rowsum[row] == 0) row++
Print Matrix;

Create a set of linear equations like;
X+ Y + .. = sum
For each row and each column.
And solve the using the standard methods of solving linear equations.

Related

Hungarian Algorithm - Wikipedia method doesn't work for this example

I'm trying to implement a Hungarian Algorithm in C.
I have the matrix:
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
And I'm up to the stage where I have to find the minimum amount of lines to cover all zeroes (making as many assignments as possible). Obviously, by inspection this is columns 1 and 3 and row 1.
Wikipedia suggests the following method:
Row 1 has three zeroes: pick any (I pick the first one) and assign it
Row 2: Assign the first zero
Row 3: Assign the 3rd zero
Row 4 is unassigned (since the only zero is in a col that already has an assigned zero)
If I follow this for my matrix above, I get:
35 0' 0 0
0' 30 0 5
55 5 0' 10
0 45 30 45
Where zero prime is the assigned zero. Then, following Wikipedia's instructions below, I mark row 4 (unassigned zero), column 1 (col with the unassigned zero), then row 2 (row with a zero in a marked col).
So that would suggest that the min lines to hit all zeroes are:
+--------
|
+--------
|
But this doesn't hit the zero at (2, 3). Relevant C code:
for (i = 0; i < M->size; i++) {
for (j = 0; j < M->size; j++) {
if (M->values[i][j] == 0) {
if (assigned_cols[j] == 0) {
assigned_cols[j] = 1; // We've assigned something in this col
assigned_rows[i] = 1; // We've assigned something in this row.
marked_rows[i] = 0;
total--;
break; // Go to the next row
} else {
marked_cols[j] = 1; // Then there exists a zero in this col in an unassigned row
mark_col(M, j); // marks all elements in column j
total++;
}
}
}
}
This code chooses which zeroes are zero prime (assigns zeroes).
Then this code marks all rows having assignments in newly-marked columns:
for (i = 0; i < M->size; i++) {
if (marked_cols[i] == 1) {
for (j = 0; j < M->size; j++) {
//iterating through rows
if (M->values[j][i] == 0) {
// then (j,i) is a zero in a marked col
// mark the row
if (marked_rows[j] != 1) {
total++;
marked_rows[j] = 1;
}
break; // no need to continue more
}
}
}
}
But this (and the wikipedia explanation) fails for my matrix above. How come?
Wikipedia is lacking explanation on the algorithm, the assignments will be done in the last step!
STEP 0
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
STEP 1-2
all rows-columns have at least one 0 so step 1 leaves array the same
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
STEP 3
All zeros in the matrix must be covered by marking as few rows and/or columns as possible
- - - -
| |
| |
| |
Note that no assignments are done thus far and you need to cover all zeros. Your cover left zero (2,3) uncovered!!
Now take min element that is not covered e.g 5 (take the 5 at position (2,4))
-Reduce (by 5) all elements that where not covered.
-Increase (by 5) all elements crossed by two lines.
-Rest remain same
So the array:
40 0 5 0
0 25 0 0
55 0 0 5
0 40 30 40
Now check again for min required lines: now you need 4 lines (equal to size n=4 of rows of array, so we stop).
Finally assignment:
Start from lines with only one zero this will surely be assigned:
40 0 5 _
0 25 _ 0
55 _ 0 5
_ 40 30 40
Multiple assignments exist (I use _ for assignment).
More specifically two assignments we get: (one stated above with total cost 5) and:
40 _ 5 0
0 25 0 _
55 0 _ 5
_ 40 30 40
With also cost 5!
EDIT
Based on comment it seems that I didn't get the exact part that op was asking so I will answer this specific part keeping the general description of the algorithm above.
The mistake (due to bad Wikipedia description) is here:
Where zero prime is the assigned zero. Then, following Wikipedia's
instructions below, I mark row 4 (unassigned zero), column 1 (col with
the unassigned zero), then row 2 (row with a zero in a marked col).
Totally agree till now but...it's not complete!!!
When correctly marking row2 you need to go to step 2 (of Wikipedia)
and check again for columns with zeros in this case column 3 should
also been marked, this also causes the row 3 to be marked as well (due to assigned zero in the newly marked column 3) and
there you stop (no other rows or columns should be marked)!!
So overall the marked columns and rows:
+ +
35 0' 0 0
0' 30 0 5 +
55 5 0' 10 +
0 45 30 45 +
And the lines you get by choosing the marked columns and unmarked lines:
- - - -
| |
| |
| |
which is the right one as described in the first part of answer and leads to right results in next stages (also explained above).
One very similar post that states literally same thing can be found on mathstackexchange:
finding the minimum number of lines to cover all zeros in an assignment probem

Matlab - removing rows and columns from a matrix that contain 0's

I'm working on a problem involving beam deflections (it's not too fun :P)
I need to reduce the global stiffness matrix into the structure stiffness matrix, I do this by removing any rows and columns from the original matrix that contain a 0.
So if I have a matrix like so (let's call it K):
0 0 5 3 0 0
0 0 7 8 0 0
7 1 2 6 2 1
3 8 6 9 5 3
0 0 4 5 0 0
0 0 1 8 0 0
The reduced matrix (let's call it S) would be just
2 6
6 9
Here's what I have written so far to reduce global matrix K to stiffness matrix S
S = K;
for i = 1:length(S(:,1))
for j = 1:length(S(1,:))
if S(i,j) == 0
S(i,:) = [];
S(:,j) = [];
break;
end
end
end
However I get "Index exceeds matrix dimensions" on the line containing the "if" statement, and I'm not sure my thinking is correct on the best way to remove all rows and columns. Appreciate any feedback!
Easy:
S = K(all(K,2), all(K,1));
For nxn matrix, alternatively you can try out matrix multiplication based approach -
K=[
0 0 5 3 2 0
0 0 7 8 7 0
7 1 6 6 2 1
3 8 6 8 5 3
0 0 4 5 5 0
5 3 7 8 1 6] %// Slightly different than the one in question
K1 = double(K~=0)
K2 = K1*K1==size(K,1)
K3 = K(K2)
S = reshape(K3,max(sum(K2,1)),max(sum(K2,2)))
Output -
S =
6 6 2
6 8 5
7 8 1
The problem is when you remove some row or column you should not increase i or j but MATLAB's for loop automatically updates them. Also your algorithm cannot handle the cases like:
0 1 0
1 1 1
1 1 1
It will only remove the first column due to break condition so you need to remove it but handle indexes properly somehow. Another approach may be firstly taking product of rows and columns then checking those products and removing the corresponding rows and columns when an element of a product is zero. An example implementation in MATLAB might be like:
function [S] = stiff(K)
S = K;
% product of each row, rows(k) == 0 if there is a 0 in row k
rows = prod(S,2);
% product of each column, cols(k) == 0 if there is a 0 in column k
cols = prod(S,1);
Here we compute the product of each row and each column
% firstly eliminate the rows
% row numbers in the new matrix
ii=1;
for i = 1:size(S,1),
if rows(i) == 0,
S(ii, :) = []; % delete the row
else
ii = ii + 1; % skip the row
end
end
Here we remove rows that contain zeros by updating the index manually (notice ii).
% handle the columns now
ii = 1;
for i = 1:size(S,2),
if cols(i) == 0,
S(:, ii) = []; % delete the row
else
ii = ii + 1; % skip the row
end
end
end
Here we apply same operation to remaining columns.
Another method I can suggest is by converting the matrix K into a logical matrix where anything that is non-zero is 1 and 0 otherwise. You would then do a column sum on this matrix then check to see if any columns don't sum to the number of rows you have. You remove these columns, then do a row sum on the intermediate matrix and check if any rows don't sum to the number of columns you have. You remove these rows to be left with your final matrix. As such:
Kbool = K ~= 0;
colsToRemove = sum(Kbool,1) ~= size(Kbool,1);
K(colsToRemove,:) = [];
rowsToRemove = sum(Kbool,2) ~= size(Kbool,2);
K(:,rowsToRemove) = [];

Matlab counting elements in array

Hey guys I just have a quick question regarding counting elements in an array.
the array is something like this
B = [1 0 1 0 0 -1; 1 1 1 0 -1 -1; 0 1 -1 0 0 1]
From this array i want to create an array structure, called column counts and another row counts. I really do want to crate an array structure, even if it is a less efficient process.
basically i want to go through the array and total for each column, row the total amount of times these values occur. For instance for the first row, i want the following output.
Row Counts
-1 0 1
1 3 2
thanks in advance
You can use the hist function to do this.
fprintf('Row counts\n');
disp([-1 0 1])
fprintf('\n')
for row = 1:3
disp(hist(m(i,:),3));
end
yields
Row counts
-1 0 1
1 3 2
2 1 3
1 3 2
I don't fully understand your question, but if you want to count the occurrences of an element in a Matlab array you can do something like:
% Find value 3 in array A
A =[ 1 4 5 3 3 1 2 4 2 3 ];
count = sum( A == 3 )
When comparing A==3 Matlab will fill an array with 0 and 1, meaning the second one that the element in the given position in A has the element you were looking for. So you can count the occurrences by accumulating the values in the array A==3
Edit: you can access the different dimensions like that:
A = [ 1 2 3 4; 1 2 3 4; 1 2 3 4 ]; % 3rows x 4columns matrix
count1 = sum( A(:,1) == 2 ); % count occurrences in the first column
count2 = sum( A(:,3) == 2 ); % ' ' third column
count3 = sum( A(2,:) == 2 ); % ' ' second row
You always access given rows or columns like that.

Vectorize the sum of unique columns

There are multiple occurrence of same combination of values in different rows of matlab, for example 1 1 in first and second row. I want to remove all those duplicates but adding the values in third column. In case of 1 1 it will be 7. Finally I want to create a similarity matrix as shown below in Answer. I don't mind 2*values in diagonals because I will not be considering diagonal elements in further work. The code below does this but it is not vectorized. Can this be vectorized somehow. Example is given below.
datain = [ 1 1 3;
1 1 4;
1 2 5;
1 2 4;
1 2 3;
1 3 8;
1 3 7;
1 3 12;
2 2 22;
2 2 77;
2 3 111;
2 3 113;
3 3 456;
3 3 568];
cmp1=unique(datain(:,1));
cmp1sz=size(cmp1,1);
cmp2=unique(datain(:,2));
cmp2sz=size(cmp2,1);
thetotal=zeros(cmp1sz,cmp2sz);
for i=1:size(datain,1)
for j=1:cmp1sz
for k=1:cmp2sz
if datain(i,1)==cmp1(j,1) && datain(i,2)== cmp2(k,1)
thetotal(j,k)=thetotal(j,k)+datain(i,3);
thetotal(k,j)=thetotal(k,j)+datain(i,3);
end
end
end
end
The answer is
14 12 27
12 198 224
27 224 2048
This is a poster case for using ACCUMARRAY.
thetotal = accumarray(datain(:,1:2),datain(:,3),[],#sum,0);
%# to make the array symmetric, you simply add its transpose
thetotal = thetotal + thetotal'
thetotal =
14 12 27
12 198 224
27 224 2048
EDIT
So what if datain does not contain only integer values? In this case, you can still construct a table, but e.g. thetotal(1,1) will not correspond to datain(1,1:2) == [1 1], but to the smallest entry in the first two columns of datain.
[uniqueVals,~,tmp] = unique(reshape(datain(:,1:2),[],1));
correspondingIndices = reshape(tmp,size(datain(:,1:2)));
thetotal = accumarray(correspondingIndices,datain(:,3),[],#sum,0);
The value at [1 1] now corresponds to the row [uniqueVals(1) uniqueVals(1)] in the first two cols of datain.

If I'm using a 1d array to represent a square board, how can I take my index and check the squares above, below and to its sides?

If I have a 4x4 gameboard which I'm representing in my program as a 1d integer array of size 16.
How can I get the indexs of the squares above, below, to the left and to the right any given index?
So, for example:
A = { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 }
Which represents this board
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
Lets say I am currently on index #8 in the board (value = 7). How can I get the index for 4 (value = 3) , 5 (value = 6), 10 (value = 11) and realize that there is no right square because it is on the right hand edge of the board.
I know I need to use some modulus math but I'm failing to come up with the right way to get the indexes for adjacent squares.
I'm thinking something like...
if ((i % 4) + 1 < 3) right = i + 1;
if ((i % 4) - 1 > 0) left = i - 1;
if ((i % 4) + 4 < 15) bottom = i + 4;
if ((i % 4) - 4 > 0 ) top = i - 4;
Does this seem like it is the right approach?
To get row,column from your index, use the following:
row = index/num_columns;
column = index % num_columns;
to get back to the index, use
index = row * num_columns + column;
One you're in rows and columns, it's easy to get the surrounding positions.
above = (row-1, column)
left = (row, column-1)
etc...

Resources