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

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

Related

How to create a function to generate a matrix where numbers progessivley get smaller columnwise? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 months ago.
Improve this question
Basically I have been trying to come up with a 2D array loop in Matlab. It will create a 5 column array for example that starts of with full 100's and removes the 5th column by an interval of 10 until it hits zero and then moves onto the 4th column and starts at 90, then the 5th column (starting at 90) goes down to zero. This repeats until all the numbers have become zero. Im looking for some sort of loop that creates something like this:
100 100 100 100 90
100 100 100 100 80
100 100 100 100 70 .....
100 100 100 90 90 .....
100 100 100 90 80
100 0 0 0 0 ....
0 0 0 0 0
But I am really struggling to come up with a simple loop for it.
If anyone has an ideas on how to create this I would really appreciate it.
Here's a simple loop-approach that does what you want. You have to make minor adjustments for it to work with the steps you want, but that should be simple:
c = 4; % number of columns
n = 3; % starting number
x = zeros(n*c+1, c); % Initial matrix of zeros
for ii = 1:c
last_idx(ii) = ((n*c+1)-n)-(ii-1)*n;
x(1:last_idx(ii),ii) = n;
x(last_idx(ii)+[1:n-1], ii) = [n-1:-1:1];
end
x =
3 3 3 3
3 3 3 2
3 3 3 1
3 3 3 0
3 3 2 0
3 3 1 0
3 3 0 0
3 2 0 0
3 1 0 0
3 0 0 0
2 0 0 0
1 0 0 0
0 0 0 0
The following should get you started. Its a very nice application possibility of the Kronecker Tensor Product to get a fully vectorized solution without loop.
Parameters:
step = 20;
nrows = 3;
nsteps = 5;
As one-liner:
A = cumsum(kron(fliplr(eye(nrows)),step*ones(nsteps,1)),1,'reverse');
with explanation:
basepattern = fliplr(eye(nrows)); % general matrix design
subpattern = step*ones(nsteps,1); % pattern to repeat
a = kron(basepattern, subpattern); % kronecker delta to repeat pattern
A = cumsum(a,1,'reverse'); % cumulative sum upwards
% optional: filter out lines:
A(nsteps+1:nsteps:end,:) = [];
% optional: pad zeros at the end
A(end+1,:) = 0
Result
A =
100 100 100
100 100 80
100 100 60
100 100 40
100 100 20
100 80 0
100 60 0
100 40 0
100 20 0
80 0 0
60 0 0
40 0 0
20 0 0
0 0 0

How to replace all occurences of elements of a two dimensional array in do loops in fortran

I've got stdin like that (elements are always > 10)
75 33 44 51
51 87 33 77
77 51 91 45
17 29 30 40
I would like to substitute 1 for one of the elements in each row (randomly - according to a random 1 =< n =< 4) and 0 for the others in the row, but so as to change equal elements throughout, i.e., 51 in the 1st, 2nd, and 3rd rows, 33 in in the 1st and 2nd rows, and 77 in the 2nd and 3rd rows but so that I don't get two 1s in a row. Assuming that n=4 for the 1st and 2nd row, and n=3 for the 3rd and 4th one, I should end up with
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
which is different from just putting n's in, i.e., I don't want
0 0 0 1
0 0 0 1
0 0 1 0
0 0 1 0
What I actually want is to change all occurrences of equal elements according to the values of their elements throughout. E.g., replacement 51 -> 1 should change 51 in the 1st, 2nd, and 3rd row to 1 as soon as 51 in the 1st row is changed to 1, but not their names. Their names c(i,j) in the array should, however, respond with their new value when called. Then, random n's should be overruled by already existing 0's and 1's in each next row, but should stay when a row is not so affected via links to the previous rows as the 4th row.
I didn't put in any Fortran specifics because I want to avoid the discussion being led astray. Constructive suggestions would be greatly appreciated.
You need to read about the WHERE construct. If I understand your description, this toy program should work for you.
program foo
implicit none
integer c(3,4), i, n
real u
c = transpose(reshape([75,33,44,51,51,87,33,77,77,51,91,45],[4,3]))
call prn ! Print original matrix
do i = 1, 3
call random_number(u)
n = 1 + floor(4*u)
print '(A,I0)', 'n = ', n
where(c(i,:) /= c(i,n)) c(i,:) = 0
where(c == c(i,n)) c = 1
call prn ! Print altered matrix
end do
contains
subroutine prn
integer i
do i = 1, 3
write(*,'(4(I0,1X))') c(i,:)
end do
print *
end subroutine prn
end program foo

Shuffle, then find and replace duplicates in two dimensional array - without sorting

I'm looking for efficient algorithm (or any at all..) for this tricky thing. I'll simplify my problem. In my application, this array is about 10000 times bigger :)
I have an 2D array like this:
0 2 1 3 4
1 2 0 4 3
0 2 1 3 4
4 1 2 3 0
Yes, in every row there are values range from 0 to 4 but in different order. The order matters! I can't just sort it and solve this in easy way :)
Then, I shuffle it by choosing a random indexes and swapping them - couple of times. Example result:
0 1 1 1 4
1 2 2 4 3
0 2 3 3 4
4 2 0 3 0
I see duplicates in the rows, that's not good.. Algorithm should find this duplicates and replace them with a value that will not be another duplicate in particular row, for example:
0 1 2 3 4
1 2 0 4 3
0 2 3 1 4
4 2 0 3 1
Can you share your ideas? Maybe there is already very famous algorithm for this problem? I'd be grateful for any hint.
EDIT
Clarification for T_G: After the shuffle, particular row can't exchange values with another rows. It need to find duplicates and replace it with available (any) value left - which is not another duplicate.
After shuffling:
0 1 1 1 4
1 2 2 4 3
0 2 3 3 4
4 2 0 3 0
Steps:
I have 0; I don't see another zeros. Next.
I have 1; I see another 1; I should change it (the second one); there is no 2 in this row, so lets change this duplicate 1 to 2.
I have 1; I see another 1. I should change it (the second one); there is no 3 in this row, so lets change this duplicate 1 to 3. etc...
So if you input this row:
0 0 0 0 0 0 0 0 0
You should get:
0 1 2 3 4 5 6 7 8
Try something like this:
// Iterate matrix lines, line by line
for(uint32_t line_no = 0; line_no < max_line_num; line_no++) {
// counters for each symbol 0-4; index is symbol, val is counter
uint8_t counters[6];
// Clear counters before usage
memset(0, counters, sizeof(counters));
// Compute counters
for(int i = 0; i < 6; i++)
counters[matrix[line_no][i]]++;
// Index of maybe unused symbol; by default is 4
int j = 4;
// Iterate line in reversed order
for(int i = 4; i >= 0; i--)
if(counters[matrix[line_no][i]] > 1) { // found dup
while(counters[j] != 0) // find unused symbol "j"
j--;
counters[matrix[line_no][i]]--; // Decrease dup counter
matrix[line_no][i] = j; // substitute dup to symbol j
counters[j]++; // this symbol j is used
} // for + if
} // for lines

Find out the column number in which Maxima occur in a matrix in Mata in a for-loop

My purpose is not to find out what the maximum value is but the column number(S) in which the maximum occurs when generated different random numbers ~N to the entire column elements of the row.
A potential problem here is what if two or more elements in the same row contain the same value which is the maximum? I know it is unlikely for they content are real numbers. But I preset all elements in first row to be zero. Therefore, in the first round, all values are maximum and are subject to next conditional action.
I will want the column number(s) to do further computation in the next round of loop
Suppose all the matrix are well defined before the for-loop to save space here.
Mata:
for (k=1; k<=10; k++){
for (j=1; j<=20; i++){
A[k,j]= sum[k,j] \ count [1,j]
}
Choose max A[k,j]
For that j* for max A[k,j*] to occur
{count[1,j*]=count[1, j*+1]
y= rnormal(1,1,x,5)
C[k,j*]=y
sum[k,j*]=sum[k,j*]+c[k,j*]
}
}
Thank you so much for your help.
I can't follow most of this -- a lot seems to be background tangential to your question -- but if the question is to find the column index of the largest element in a row vector, here is one technique:
: y = rnormal(1,10,0,1)
: y
1 2 3 4 5
+----------------------------------------------------------------------------
1 | .3660763572 .4824003439 -.4441589685 .4314199623 -1.422563986
+----------------------------------------------------------------------------
6 7 8 9 10
----------------------------------------------------------------------------+
1 -1.226056129 1.18790502 -.4106889581 1.024620896 1.092570732 |
----------------------------------------------------------------------------+
: select((1..10), (y :== max(y)))
7
(LATER)
I haven't tried to grasp the whole of what you are trying to do, but you are making very bold assertions about a language you have only just started to learn.
Generally, select() will take a matrix as first argument.
Specifically, there is no problem in identifying the maximum in a matrix.
: y = rnormal(5,5,0,1)
: max(y)
2.001071729
: y :== max(y)
1 2 3 4 5
+---------------------+
1 | 0 0 0 0 0 |
2 | 0 0 0 0 1 |
3 | 0 0 0 0 0 |
4 | 0 0 0 0 0 |
5 | 0 0 0 0 0 |
+---------------------+
I hope that helps a bit.
for (k=2; k<=n; k++){
for (j=1; j<=50; j++){
Ri[k,j]= sumAi[1,j] / count[1,j]
}
Maxj= select((1..50), (Ri[k,]:==max(Ri[k,])))
count[1,Maxj]=count[1,Maxj]+1
y= rnormal(1,1,x,5)
Ai[k,Maxj]=y
sumAi[1,Maxj]=sumAi[1,Maxj]+y
Maxj=.
}

Algorithm to get the entries of a table?

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.

Resources