annotate toolboxes/FullBNT-1.0.7/KPMtools/hungarian.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 function [C,T]=hungarian(A)
wolffd@0 2 %HUNGARIAN Solve the Assignment problem using the Hungarian method.
wolffd@0 3 %
wolffd@0 4 %[C,T]=hungarian(A)
wolffd@0 5 %A - a square cost matrix.
wolffd@0 6 %C - the optimal assignment.
wolffd@0 7 %T - the cost of the optimal assignment.
wolffd@0 8
wolffd@0 9 % Adapted from the FORTRAN IV code in Carpaneto and Toth, "Algorithm 548:
wolffd@0 10 % Solution of the assignment problem [H]", ACM Transactions on
wolffd@0 11 % Mathematical Software, 6(1):104-111, 1980.
wolffd@0 12
wolffd@0 13 % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
wolffd@0 14 % Department of Computing Science, Umeå University,
wolffd@0 15 % Sweden.
wolffd@0 16 % All standard disclaimers apply.
wolffd@0 17
wolffd@0 18 % A substantial effort was put into this code. If you use it for a
wolffd@0 19 % publication or otherwise, please include an acknowledgement or at least
wolffd@0 20 % notify me by email. /Niclas
wolffd@0 21
wolffd@0 22 [m,n]=size(A);
wolffd@0 23
wolffd@0 24 if (m~=n)
wolffd@0 25 error('HUNGARIAN: Cost matrix must be square!');
wolffd@0 26 end
wolffd@0 27
wolffd@0 28 % Save original cost matrix.
wolffd@0 29 orig=A;
wolffd@0 30
wolffd@0 31 % Reduce matrix.
wolffd@0 32 A=hminired(A);
wolffd@0 33
wolffd@0 34 % Do an initial assignment.
wolffd@0 35 [A,C,U]=hminiass(A);
wolffd@0 36
wolffd@0 37 % Repeat while we have unassigned rows.
wolffd@0 38 while (U(n+1))
wolffd@0 39 % Start with no path, no unchecked zeros, and no unexplored rows.
wolffd@0 40 LR=zeros(1,n);
wolffd@0 41 LC=zeros(1,n);
wolffd@0 42 CH=zeros(1,n);
wolffd@0 43 RH=[zeros(1,n) -1];
wolffd@0 44
wolffd@0 45 % No labelled columns.
wolffd@0 46 SLC=[];
wolffd@0 47
wolffd@0 48 % Start path in first unassigned row.
wolffd@0 49 r=U(n+1);
wolffd@0 50 % Mark row with end-of-path label.
wolffd@0 51 LR(r)=-1;
wolffd@0 52 % Insert row first in labelled row set.
wolffd@0 53 SLR=r;
wolffd@0 54
wolffd@0 55 % Repeat until we manage to find an assignable zero.
wolffd@0 56 while (1)
wolffd@0 57 % If there are free zeros in row r
wolffd@0 58 if (A(r,n+1)~=0)
wolffd@0 59 % ...get column of first free zero.
wolffd@0 60 l=-A(r,n+1);
wolffd@0 61
wolffd@0 62 % If there are more free zeros in row r and row r in not
wolffd@0 63 % yet marked as unexplored..
wolffd@0 64 if (A(r,l)~=0 & RH(r)==0)
wolffd@0 65 % Insert row r first in unexplored list.
wolffd@0 66 RH(r)=RH(n+1);
wolffd@0 67 RH(n+1)=r;
wolffd@0 68
wolffd@0 69 % Mark in which column the next unexplored zero in this row
wolffd@0 70 % is.
wolffd@0 71 CH(r)=-A(r,l);
wolffd@0 72 end
wolffd@0 73 else
wolffd@0 74 % If all rows are explored..
wolffd@0 75 if (RH(n+1)<=0)
wolffd@0 76 % Reduce matrix.
wolffd@0 77 [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR);
wolffd@0 78 end
wolffd@0 79
wolffd@0 80 % Re-start with first unexplored row.
wolffd@0 81 r=RH(n+1);
wolffd@0 82 % Get column of next free zero in row r.
wolffd@0 83 l=CH(r);
wolffd@0 84 % Advance "column of next free zero".
wolffd@0 85 CH(r)=-A(r,l);
wolffd@0 86 % If this zero is last in the list..
wolffd@0 87 if (A(r,l)==0)
wolffd@0 88 % ...remove row r from unexplored list.
wolffd@0 89 RH(n+1)=RH(r);
wolffd@0 90 RH(r)=0;
wolffd@0 91 end
wolffd@0 92 end
wolffd@0 93
wolffd@0 94 % While the column l is labelled, i.e. in path.
wolffd@0 95 while (LC(l)~=0)
wolffd@0 96 % If row r is explored..
wolffd@0 97 if (RH(r)==0)
wolffd@0 98 % If all rows are explored..
wolffd@0 99 if (RH(n+1)<=0)
wolffd@0 100 % Reduce cost matrix.
wolffd@0 101 [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR);
wolffd@0 102 end
wolffd@0 103
wolffd@0 104 % Re-start with first unexplored row.
wolffd@0 105 r=RH(n+1);
wolffd@0 106 end
wolffd@0 107
wolffd@0 108 % Get column of next free zero in row r.
wolffd@0 109 l=CH(r);
wolffd@0 110
wolffd@0 111 % Advance "column of next free zero".
wolffd@0 112 CH(r)=-A(r,l);
wolffd@0 113
wolffd@0 114 % If this zero is last in list..
wolffd@0 115 if(A(r,l)==0)
wolffd@0 116 % ...remove row r from unexplored list.
wolffd@0 117 RH(n+1)=RH(r);
wolffd@0 118 RH(r)=0;
wolffd@0 119 end
wolffd@0 120 end
wolffd@0 121
wolffd@0 122 % If the column found is unassigned..
wolffd@0 123 if (C(l)==0)
wolffd@0 124 % Flip all zeros along the path in LR,LC.
wolffd@0 125 [A,C,U]=hmflip(A,C,LC,LR,U,l,r);
wolffd@0 126 % ...and exit to continue with next unassigned row.
wolffd@0 127 break;
wolffd@0 128 else
wolffd@0 129 % ...else add zero to path.
wolffd@0 130
wolffd@0 131 % Label column l with row r.
wolffd@0 132 LC(l)=r;
wolffd@0 133
wolffd@0 134 % Add l to the set of labelled columns.
wolffd@0 135 SLC=[SLC l];
wolffd@0 136
wolffd@0 137 % Continue with the row assigned to column l.
wolffd@0 138 r=C(l);
wolffd@0 139
wolffd@0 140 % Label row r with column l.
wolffd@0 141 LR(r)=l;
wolffd@0 142
wolffd@0 143 % Add r to the set of labelled rows.
wolffd@0 144 SLR=[SLR r];
wolffd@0 145 end
wolffd@0 146 end
wolffd@0 147 end
wolffd@0 148
wolffd@0 149 % Calculate the total cost.
wolffd@0 150 T=sum(orig(logical(sparse(C,1:size(orig,2),1))));
wolffd@0 151
wolffd@0 152
wolffd@0 153 function A=hminired(A)
wolffd@0 154 %HMINIRED Initial reduction of cost matrix for the Hungarian method.
wolffd@0 155 %
wolffd@0 156 %B=assredin(A)
wolffd@0 157 %A - the unreduced cost matris.
wolffd@0 158 %B - the reduced cost matrix with linked zeros in each row.
wolffd@0 159
wolffd@0 160 % v1.0 96-06-13. Niclas Borlin, niclas@cs.umu.se.
wolffd@0 161
wolffd@0 162 [m,n]=size(A);
wolffd@0 163
wolffd@0 164 % Subtract column-minimum values from each column.
wolffd@0 165 colMin=min(A);
wolffd@0 166 A=A-colMin(ones(n,1),:);
wolffd@0 167
wolffd@0 168 % Subtract row-minimum values from each row.
wolffd@0 169 rowMin=min(A')';
wolffd@0 170 A=A-rowMin(:,ones(1,n));
wolffd@0 171
wolffd@0 172 % Get positions of all zeros.
wolffd@0 173 [i,j]=find(A==0);
wolffd@0 174
wolffd@0 175 % Extend A to give room for row zero list header column.
wolffd@0 176 A(1,n+1)=0;
wolffd@0 177 for k=1:n
wolffd@0 178 % Get all column in this row.
wolffd@0 179 cols=j(k==i)';
wolffd@0 180 % Insert pointers in matrix.
wolffd@0 181 A(k,[n+1 cols])=[-cols 0];
wolffd@0 182 end
wolffd@0 183
wolffd@0 184
wolffd@0 185 function [A,C,U]=hminiass(A)
wolffd@0 186 %HMINIASS Initial assignment of the Hungarian method.
wolffd@0 187 %
wolffd@0 188 %[B,C,U]=hminiass(A)
wolffd@0 189 %A - the reduced cost matrix.
wolffd@0 190 %B - the reduced cost matrix, with assigned zeros removed from lists.
wolffd@0 191 %C - a vector. C(J)=I means row I is assigned to column J,
wolffd@0 192 % i.e. there is an assigned zero in position I,J.
wolffd@0 193 %U - a vector with a linked list of unassigned rows.
wolffd@0 194
wolffd@0 195 % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
wolffd@0 196
wolffd@0 197 [n,np1]=size(A);
wolffd@0 198
wolffd@0 199 % Initalize return vectors.
wolffd@0 200 C=zeros(1,n);
wolffd@0 201 U=zeros(1,n+1);
wolffd@0 202
wolffd@0 203 % Initialize last/next zero "pointers".
wolffd@0 204 LZ=zeros(1,n);
wolffd@0 205 NZ=zeros(1,n);
wolffd@0 206
wolffd@0 207 for i=1:n
wolffd@0 208 % Set j to first unassigned zero in row i.
wolffd@0 209 lj=n+1;
wolffd@0 210 j=-A(i,lj);
wolffd@0 211
wolffd@0 212 % Repeat until we have no more zeros (j==0) or we find a zero
wolffd@0 213 % in an unassigned column (c(j)==0).
wolffd@0 214
wolffd@0 215 while (C(j)~=0)
wolffd@0 216 % Advance lj and j in zero list.
wolffd@0 217 lj=j;
wolffd@0 218 j=-A(i,lj);
wolffd@0 219
wolffd@0 220 % Stop if we hit end of list.
wolffd@0 221 if (j==0)
wolffd@0 222 break;
wolffd@0 223 end
wolffd@0 224 end
wolffd@0 225
wolffd@0 226 if (j~=0)
wolffd@0 227 % We found a zero in an unassigned column.
wolffd@0 228
wolffd@0 229 % Assign row i to column j.
wolffd@0 230 C(j)=i;
wolffd@0 231
wolffd@0 232 % Remove A(i,j) from unassigned zero list.
wolffd@0 233 A(i,lj)=A(i,j);
wolffd@0 234
wolffd@0 235 % Update next/last unassigned zero pointers.
wolffd@0 236 NZ(i)=-A(i,j);
wolffd@0 237 LZ(i)=lj;
wolffd@0 238
wolffd@0 239 % Indicate A(i,j) is an assigned zero.
wolffd@0 240 A(i,j)=0;
wolffd@0 241 else
wolffd@0 242 % We found no zero in an unassigned column.
wolffd@0 243
wolffd@0 244 % Check all zeros in this row.
wolffd@0 245
wolffd@0 246 lj=n+1;
wolffd@0 247 j=-A(i,lj);
wolffd@0 248
wolffd@0 249 % Check all zeros in this row for a suitable zero in another row.
wolffd@0 250 while (j~=0)
wolffd@0 251 % Check the in the row assigned to this column.
wolffd@0 252 r=C(j);
wolffd@0 253
wolffd@0 254 % Pick up last/next pointers.
wolffd@0 255 lm=LZ(r);
wolffd@0 256 m=NZ(r);
wolffd@0 257
wolffd@0 258 % Check all unchecked zeros in free list of this row.
wolffd@0 259 while (m~=0)
wolffd@0 260 % Stop if we find an unassigned column.
wolffd@0 261 if (C(m)==0)
wolffd@0 262 break;
wolffd@0 263 end
wolffd@0 264
wolffd@0 265 % Advance one step in list.
wolffd@0 266 lm=m;
wolffd@0 267 m=-A(r,lm);
wolffd@0 268 end
wolffd@0 269
wolffd@0 270 if (m==0)
wolffd@0 271 % We failed on row r. Continue with next zero on row i.
wolffd@0 272 lj=j;
wolffd@0 273 j=-A(i,lj);
wolffd@0 274 else
wolffd@0 275 % We found a zero in an unassigned column.
wolffd@0 276
wolffd@0 277 % Replace zero at (r,m) in unassigned list with zero at (r,j)
wolffd@0 278 A(r,lm)=-j;
wolffd@0 279 A(r,j)=A(r,m);
wolffd@0 280
wolffd@0 281 % Update last/next pointers in row r.
wolffd@0 282 NZ(r)=-A(r,m);
wolffd@0 283 LZ(r)=j;
wolffd@0 284
wolffd@0 285 % Mark A(r,m) as an assigned zero in the matrix . . .
wolffd@0 286 A(r,m)=0;
wolffd@0 287
wolffd@0 288 % ...and in the assignment vector.
wolffd@0 289 C(m)=r;
wolffd@0 290
wolffd@0 291 % Remove A(i,j) from unassigned list.
wolffd@0 292 A(i,lj)=A(i,j);
wolffd@0 293
wolffd@0 294 % Update last/next pointers in row r.
wolffd@0 295 NZ(i)=-A(i,j);
wolffd@0 296 LZ(i)=lj;
wolffd@0 297
wolffd@0 298 % Mark A(r,m) as an assigned zero in the matrix . . .
wolffd@0 299 A(i,j)=0;
wolffd@0 300
wolffd@0 301 % ...and in the assignment vector.
wolffd@0 302 C(j)=i;
wolffd@0 303
wolffd@0 304 % Stop search.
wolffd@0 305 break;
wolffd@0 306 end
wolffd@0 307 end
wolffd@0 308 end
wolffd@0 309 end
wolffd@0 310
wolffd@0 311 % Create vector with list of unassigned rows.
wolffd@0 312
wolffd@0 313 % Mark all rows have assignment.
wolffd@0 314 r=zeros(1,n);
wolffd@0 315 rows=C(C~=0);
wolffd@0 316 r(rows)=rows;
wolffd@0 317 empty=find(r==0);
wolffd@0 318
wolffd@0 319 % Create vector with linked list of unassigned rows.
wolffd@0 320 U=zeros(1,n+1);
wolffd@0 321 U([n+1 empty])=[empty 0];
wolffd@0 322
wolffd@0 323
wolffd@0 324 function [A,C,U]=hmflip(A,C,LC,LR,U,l,r)
wolffd@0 325 %HMFLIP Flip assignment state of all zeros along a path.
wolffd@0 326 %
wolffd@0 327 %[A,C,U]=hmflip(A,C,LC,LR,U,l,r)
wolffd@0 328 %Input:
wolffd@0 329 %A - the cost matrix.
wolffd@0 330 %C - the assignment vector.
wolffd@0 331 %LC - the column label vector.
wolffd@0 332 %LR - the row label vector.
wolffd@0 333 %U - the
wolffd@0 334 %r,l - position of last zero in path.
wolffd@0 335 %Output:
wolffd@0 336 %A - updated cost matrix.
wolffd@0 337 %C - updated assignment vector.
wolffd@0 338 %U - updated unassigned row list vector.
wolffd@0 339
wolffd@0 340 % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
wolffd@0 341
wolffd@0 342 n=size(A,1);
wolffd@0 343
wolffd@0 344 while (1)
wolffd@0 345 % Move assignment in column l to row r.
wolffd@0 346 C(l)=r;
wolffd@0 347
wolffd@0 348 % Find zero to be removed from zero list..
wolffd@0 349
wolffd@0 350 % Find zero before this.
wolffd@0 351 m=find(A(r,:)==-l);
wolffd@0 352
wolffd@0 353 % Link past this zero.
wolffd@0 354 A(r,m)=A(r,l);
wolffd@0 355
wolffd@0 356 A(r,l)=0;
wolffd@0 357
wolffd@0 358 % If this was the first zero of the path..
wolffd@0 359 if (LR(r)<0)
wolffd@0 360 ...remove row from unassigned row list and return.
wolffd@0 361 U(n+1)=U(r);
wolffd@0 362 U(r)=0;
wolffd@0 363 return;
wolffd@0 364 else
wolffd@0 365
wolffd@0 366 % Move back in this row along the path and get column of next zero.
wolffd@0 367 l=LR(r);
wolffd@0 368
wolffd@0 369 % Insert zero at (r,l) first in zero list.
wolffd@0 370 A(r,l)=A(r,n+1);
wolffd@0 371 A(r,n+1)=-l;
wolffd@0 372
wolffd@0 373 % Continue back along the column to get row of next zero in path.
wolffd@0 374 r=LC(l);
wolffd@0 375 end
wolffd@0 376 end
wolffd@0 377
wolffd@0 378
wolffd@0 379 function [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR)
wolffd@0 380 %HMREDUCE Reduce parts of cost matrix in the Hungerian method.
wolffd@0 381 %
wolffd@0 382 %[A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR)
wolffd@0 383 %Input:
wolffd@0 384 %A - Cost matrix.
wolffd@0 385 %CH - vector of column of 'next zeros' in each row.
wolffd@0 386 %RH - vector with list of unexplored rows.
wolffd@0 387 %LC - column labels.
wolffd@0 388 %RC - row labels.
wolffd@0 389 %SLC - set of column labels.
wolffd@0 390 %SLR - set of row labels.
wolffd@0 391 %
wolffd@0 392 %Output:
wolffd@0 393 %A - Reduced cost matrix.
wolffd@0 394 %CH - Updated vector of 'next zeros' in each row.
wolffd@0 395 %RH - Updated vector of unexplored rows.
wolffd@0 396
wolffd@0 397 % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
wolffd@0 398
wolffd@0 399 n=size(A,1);
wolffd@0 400
wolffd@0 401 % Find which rows are covered, i.e. unlabelled.
wolffd@0 402 coveredRows=LR==0;
wolffd@0 403
wolffd@0 404 % Find which columns are covered, i.e. labelled.
wolffd@0 405 coveredCols=LC~=0;
wolffd@0 406
wolffd@0 407 r=find(~coveredRows);
wolffd@0 408 c=find(~coveredCols);
wolffd@0 409
wolffd@0 410 % Get minimum of uncovered elements.
wolffd@0 411 m=min(min(A(r,c)));
wolffd@0 412
wolffd@0 413 % Subtract minimum from all uncovered elements.
wolffd@0 414 A(r,c)=A(r,c)-m;
wolffd@0 415
wolffd@0 416 % Check all uncovered columns..
wolffd@0 417 for j=c
wolffd@0 418 % ...and uncovered rows in path order..
wolffd@0 419 for i=SLR
wolffd@0 420 % If this is a (new) zero..
wolffd@0 421 if (A(i,j)==0)
wolffd@0 422 % If the row is not in unexplored list..
wolffd@0 423 if (RH(i)==0)
wolffd@0 424 % ...insert it first in unexplored list.
wolffd@0 425 RH(i)=RH(n+1);
wolffd@0 426 RH(n+1)=i;
wolffd@0 427 % Mark this zero as "next free" in this row.
wolffd@0 428 CH(i)=j;
wolffd@0 429 end
wolffd@0 430 % Find last unassigned zero on row I.
wolffd@0 431 row=A(i,:);
wolffd@0 432 colsInList=-row(row<0);
wolffd@0 433 if (length(colsInList)==0)
wolffd@0 434 % No zeros in the list.
wolffd@0 435 l=n+1;
wolffd@0 436 else
wolffd@0 437 l=colsInList(row(colsInList)==0);
wolffd@0 438 end
wolffd@0 439 % Append this zero to end of list.
wolffd@0 440 A(i,l)=-j;
wolffd@0 441 end
wolffd@0 442 end
wolffd@0 443 end
wolffd@0 444
wolffd@0 445 % Add minimum to all doubly covered elements.
wolffd@0 446 r=find(coveredRows);
wolffd@0 447 c=find(coveredCols);
wolffd@0 448
wolffd@0 449 % Take care of the zeros we will remove.
wolffd@0 450 [i,j]=find(A(r,c)<=0);
wolffd@0 451
wolffd@0 452 i=r(i);
wolffd@0 453 j=c(j);
wolffd@0 454
wolffd@0 455 for k=1:length(i)
wolffd@0 456 % Find zero before this in this row.
wolffd@0 457 lj=find(A(i(k),:)==-j(k));
wolffd@0 458 % Link past it.
wolffd@0 459 A(i(k),lj)=A(i(k),j(k));
wolffd@0 460 % Mark it as assigned.
wolffd@0 461 A(i(k),j(k))=0;
wolffd@0 462 end
wolffd@0 463
wolffd@0 464 A(r,c)=A(r,c)+m;