diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolboxes/FullBNT-1.0.7/KPMtools/hungarian.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,464 @@
+function [C,T]=hungarian(A)
+%HUNGARIAN Solve the Assignment problem using the Hungarian method.
+%
+%[C,T]=hungarian(A)
+%A - a square cost matrix.
+%C - the optimal assignment.
+%T - the cost of the optimal assignment.
+
+% Adapted from the FORTRAN IV code in Carpaneto and Toth, "Algorithm 548:
+% Solution of the assignment problem [H]", ACM Transactions on
+% Mathematical Software, 6(1):104-111, 1980.
+
+% v1.0  96-06-14. Niclas Borlin, niclas@cs.umu.se.
+%                 Department of Computing Science, Umeå University,
+%                 Sweden. 
+%                 All standard disclaimers apply.
+
+% A substantial effort was put into this code. If you use it for a
+% publication or otherwise, please include an acknowledgement or at least
+% notify me by email. /Niclas
+
+[m,n]=size(A);
+
+if (m~=n)
+    error('HUNGARIAN: Cost matrix must be square!');
+end
+
+% Save original cost matrix.
+orig=A;
+
+% Reduce matrix.
+A=hminired(A);
+
+% Do an initial assignment.
+[A,C,U]=hminiass(A);
+
+% Repeat while we have unassigned rows.
+while (U(n+1))
+    % Start with no path, no unchecked zeros, and no unexplored rows.
+    LR=zeros(1,n);
+    LC=zeros(1,n);
+    CH=zeros(1,n);
+    RH=[zeros(1,n) -1];
+    
+    % No labelled columns.
+    SLC=[];
+    
+    % Start path in first unassigned row.
+    r=U(n+1);
+    % Mark row with end-of-path label.
+    LR(r)=-1;
+    % Insert row first in labelled row set.
+    SLR=r;
+    
+    % Repeat until we manage to find an assignable zero.
+    while (1)
+        % If there are free zeros in row r
+        if (A(r,n+1)~=0)
+            % ...get column of first free zero.
+            l=-A(r,n+1);
+            
+            % If there are more free zeros in row r and row r in not
+            % yet marked as unexplored..
+            if (A(r,l)~=0 & RH(r)==0)
+                % Insert row r first in unexplored list.
+                RH(r)=RH(n+1);
+                RH(n+1)=r;
+                
+                % Mark in which column the next unexplored zero in this row
+                % is.
+                CH(r)=-A(r,l);
+            end
+        else
+            % If all rows are explored..
+            if (RH(n+1)<=0)
+                % Reduce matrix.
+                [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR);
+            end
+            
+            % Re-start with first unexplored row.
+            r=RH(n+1);
+            % Get column of next free zero in row r.
+            l=CH(r);
+            % Advance "column of next free zero".
+            CH(r)=-A(r,l);
+            % If this zero is last in the list..
+            if (A(r,l)==0)
+                % ...remove row r from unexplored list.
+                RH(n+1)=RH(r);
+                RH(r)=0;
+            end
+        end
+        
+        % While the column l is labelled, i.e. in path.
+        while (LC(l)~=0)
+            % If row r is explored..
+            if (RH(r)==0)
+                % If all rows are explored..
+                if (RH(n+1)<=0)
+                    % Reduce cost matrix.
+                    [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR);
+                end
+                
+                % Re-start with first unexplored row.
+                r=RH(n+1);
+            end
+            
+            % Get column of next free zero in row r.
+            l=CH(r);
+            
+            % Advance "column of next free zero".
+            CH(r)=-A(r,l);
+            
+            % If this zero is last in list..
+            if(A(r,l)==0)
+                % ...remove row r from unexplored list.
+                RH(n+1)=RH(r);
+                RH(r)=0;
+            end
+        end
+        
+        % If the column found is unassigned..
+        if (C(l)==0)
+            % Flip all zeros along the path in LR,LC.
+            [A,C,U]=hmflip(A,C,LC,LR,U,l,r);
+            % ...and exit to continue with next unassigned row.
+            break;
+        else
+            % ...else add zero to path.
+            
+            % Label column l with row r.
+            LC(l)=r;
+            
+            % Add l to the set of labelled columns.
+            SLC=[SLC l];
+            
+            % Continue with the row assigned to column l.
+            r=C(l);
+            
+            % Label row r with column l.
+            LR(r)=l;
+            
+            % Add r to the set of labelled rows.
+            SLR=[SLR r];
+        end
+    end
+end
+
+% Calculate the total cost.
+T=sum(orig(logical(sparse(C,1:size(orig,2),1))));
+
+
+function A=hminired(A)
+%HMINIRED Initial reduction of cost matrix for the Hungarian method.
+%
+%B=assredin(A)
+%A - the unreduced cost matris.
+%B - the reduced cost matrix with linked zeros in each row.
+
+% v1.0  96-06-13. Niclas Borlin, niclas@cs.umu.se.
+
+[m,n]=size(A);
+
+% Subtract column-minimum values from each column.
+colMin=min(A);
+A=A-colMin(ones(n,1),:);
+
+% Subtract row-minimum values from each row.
+rowMin=min(A')';
+A=A-rowMin(:,ones(1,n));
+
+% Get positions of all zeros.
+[i,j]=find(A==0);
+
+% Extend A to give room for row zero list header column.
+A(1,n+1)=0;
+for k=1:n
+    % Get all column in this row. 
+    cols=j(k==i)';
+    % Insert pointers in matrix.
+    A(k,[n+1 cols])=[-cols 0];
+end
+
+
+function [A,C,U]=hminiass(A)
+%HMINIASS Initial assignment of the Hungarian method.
+%
+%[B,C,U]=hminiass(A)
+%A - the reduced cost matrix.
+%B - the reduced cost matrix, with assigned zeros removed from lists.
+%C - a vector. C(J)=I means row I is assigned to column J,
+%              i.e. there is an assigned zero in position I,J.
+%U - a vector with a linked list of unassigned rows.
+
+% v1.0  96-06-14. Niclas Borlin, niclas@cs.umu.se.
+
+[n,np1]=size(A);
+
+% Initalize return vectors.
+C=zeros(1,n);
+U=zeros(1,n+1);
+
+% Initialize last/next zero "pointers".
+LZ=zeros(1,n);
+NZ=zeros(1,n);
+
+for i=1:n
+    % Set j to first unassigned zero in row i.
+	lj=n+1;
+	j=-A(i,lj);
+
+    % Repeat until we have no more zeros (j==0) or we find a zero
+	% in an unassigned column (c(j)==0).
+    
+	while (C(j)~=0)
+		% Advance lj and j in zero list.
+		lj=j;
+		j=-A(i,lj);
+	
+		% Stop if we hit end of list.
+		if (j==0)
+			break;
+		end
+	end
+
+	if (j~=0)
+		% We found a zero in an unassigned column.
+		
+		% Assign row i to column j.
+		C(j)=i;
+		
+		% Remove A(i,j) from unassigned zero list.
+		A(i,lj)=A(i,j);
+
+		% Update next/last unassigned zero pointers.
+		NZ(i)=-A(i,j);
+		LZ(i)=lj;
+
+		% Indicate A(i,j) is an assigned zero.
+		A(i,j)=0;
+	else
+		% We found no zero in an unassigned column.
+
+		% Check all zeros in this row.
+
+		lj=n+1;
+		j=-A(i,lj);
+		
+		% Check all zeros in this row for a suitable zero in another row.
+		while (j~=0)
+			% Check the in the row assigned to this column.
+			r=C(j);
+			
+			% Pick up last/next pointers.
+			lm=LZ(r);
+			m=NZ(r);
+			
+			% Check all unchecked zeros in free list of this row.
+			while (m~=0)
+				% Stop if we find an unassigned column.
+				if (C(m)==0)
+					break;
+				end
+				
+				% Advance one step in list.
+				lm=m;
+				m=-A(r,lm);
+			end
+			
+			if (m==0)
+				% We failed on row r. Continue with next zero on row i.
+				lj=j;
+				j=-A(i,lj);
+			else
+				% We found a zero in an unassigned column.
+			
+				% Replace zero at (r,m) in unassigned list with zero at (r,j)
+				A(r,lm)=-j;
+				A(r,j)=A(r,m);
+			
+				% Update last/next pointers in row r.
+				NZ(r)=-A(r,m);
+				LZ(r)=j;
+			
+				% Mark A(r,m) as an assigned zero in the matrix . . .
+				A(r,m)=0;
+			
+				% ...and in the assignment vector.
+				C(m)=r;
+			
+				% Remove A(i,j) from unassigned list.
+				A(i,lj)=A(i,j);
+			
+				% Update last/next pointers in row r.
+				NZ(i)=-A(i,j);
+				LZ(i)=lj;
+			
+				% Mark A(r,m) as an assigned zero in the matrix . . .
+				A(i,j)=0;
+			
+				% ...and in the assignment vector.
+				C(j)=i;
+				
+				% Stop search.
+				break;
+			end
+		end
+	end
+end
+
+% Create vector with list of unassigned rows.
+
+% Mark all rows have assignment.
+r=zeros(1,n);
+rows=C(C~=0);
+r(rows)=rows;
+empty=find(r==0);
+
+% Create vector with linked list of unassigned rows.
+U=zeros(1,n+1);
+U([n+1 empty])=[empty 0];
+
+
+function [A,C,U]=hmflip(A,C,LC,LR,U,l,r)
+%HMFLIP Flip assignment state of all zeros along a path.
+%
+%[A,C,U]=hmflip(A,C,LC,LR,U,l,r)
+%Input:
+%A   - the cost matrix.
+%C   - the assignment vector.
+%LC  - the column label vector.
+%LR  - the row label vector.
+%U   - the 
+%r,l - position of last zero in path.
+%Output:
+%A   - updated cost matrix.
+%C   - updated assignment vector.
+%U   - updated unassigned row list vector.
+
+% v1.0  96-06-14. Niclas Borlin, niclas@cs.umu.se.
+
+n=size(A,1);
+
+while (1)
+    % Move assignment in column l to row r.
+    C(l)=r;
+    
+    % Find zero to be removed from zero list..
+    
+    % Find zero before this.
+    m=find(A(r,:)==-l);
+    
+    % Link past this zero.
+    A(r,m)=A(r,l);
+    
+    A(r,l)=0;
+    
+    % If this was the first zero of the path..
+    if (LR(r)<0)
+        ...remove row from unassigned row list and return.
+        U(n+1)=U(r);
+        U(r)=0;
+        return;
+    else
+        
+        % Move back in this row along the path and get column of next zero.
+        l=LR(r);
+        
+        % Insert zero at (r,l) first in zero list.
+        A(r,l)=A(r,n+1);
+        A(r,n+1)=-l;
+        
+        % Continue back along the column to get row of next zero in path.
+        r=LC(l);
+    end
+end
+
+
+function [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR)
+%HMREDUCE Reduce parts of cost matrix in the Hungerian method.
+%
+%[A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR)
+%Input:
+%A   - Cost matrix.
+%CH  - vector of column of 'next zeros' in each row.
+%RH  - vector with list of unexplored rows.
+%LC  - column labels.
+%RC  - row labels.
+%SLC - set of column labels.
+%SLR - set of row labels.
+%
+%Output:
+%A   - Reduced cost matrix.
+%CH  - Updated vector of 'next zeros' in each row.
+%RH  - Updated vector of unexplored rows.
+
+% v1.0  96-06-14. Niclas Borlin, niclas@cs.umu.se.
+
+n=size(A,1);
+
+% Find which rows are covered, i.e. unlabelled.
+coveredRows=LR==0;
+
+% Find which columns are covered, i.e. labelled.
+coveredCols=LC~=0;
+
+r=find(~coveredRows);
+c=find(~coveredCols);
+
+% Get minimum of uncovered elements.
+m=min(min(A(r,c)));
+
+% Subtract minimum from all uncovered elements.
+A(r,c)=A(r,c)-m;
+
+% Check all uncovered columns..
+for j=c
+    % ...and uncovered rows in path order..
+    for i=SLR
+        % If this is a (new) zero..
+        if (A(i,j)==0)
+            % If the row is not in unexplored list..
+            if (RH(i)==0)
+                % ...insert it first in unexplored list.
+                RH(i)=RH(n+1);
+                RH(n+1)=i;
+                % Mark this zero as "next free" in this row.
+                CH(i)=j;
+            end
+            % Find last unassigned zero on row I.
+            row=A(i,:);
+            colsInList=-row(row<0);
+            if (length(colsInList)==0)
+                % No zeros in the list.
+                l=n+1;
+            else
+                l=colsInList(row(colsInList)==0);
+            end
+            % Append this zero to end of list.
+            A(i,l)=-j;
+        end
+    end
+end
+
+% Add minimum to all doubly covered elements.
+r=find(coveredRows);
+c=find(coveredCols);
+
+% Take care of the zeros we will remove.
+[i,j]=find(A(r,c)<=0);
+
+i=r(i);
+j=c(j);
+
+for k=1:length(i)
+    % Find zero before this in this row.
+    lj=find(A(i(k),:)==-j(k));
+    % Link past it.
+    A(i(k),lj)=A(i(k),j(k));
+    % Mark it as assigned.
+    A(i(k),j(k))=0;
+end
+
+A(r,c)=A(r,c)+m;