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

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