somtoolbox2/som_distortion.m
4dbef185
 function [adm,admu,tdmu] = som_distortion(sM, D, arg1, arg2)
 
 %SOM_DISTORTION Calculate distortion measure for the map.
 %
 % [adm,admu,tdmu] = som_distortion(sMap, D, [radius], ['prob'])
 %
 %  adm = som_distortion(sMap,D);
 %  [adm,admu] = som_distortion(sMap,D);
 %  som_show(sMap,'color',admu);
 %
 %  Input and output arguments: 
 %   sMap     (struct) a map struct
 %   D        (struct) a data struct
 %            (matrix) size dlen x dim, a data matrix
 %   [radius] (scalar) neighborhood function radius to be used.
 %                     Defaults to the last radius_fin in the 
 %                     trainhist field of the map struct, or 1 if
 %                     that is missing.
 %   ['prob'] (string) If given, this argument forces the 
 %                     neigborhood function values for each map
 %                     unit to be normalized so that they sum to 1.
 %
 %   adm      (scalar) average distortion measure (sum(dm)/dlen)
 %   admu     (vector) size munits x 1, average distortion in each unit 
 %   tdmu     (vector) size munits x 1, total distortion for each unit
 %
 % The distortion measure is defined as: 
 %                                           2
 %    E = sum sum h(bmu(i),j) ||m(j) - x(i)|| 
 %         i   j    
 % 
 % where m(i) is the ith prototype vector of SOM, x(j) is the jth data
 % vector, and h(.,.) is the neighborhood function. In case of fixed
 % neighborhood and discreet data, the distortion measure can be
 % interpreted as the energy function of the SOM. Note, though, that
 % the learning rule that follows from the distortion measure is
 % different from the SOM training rule, so SOM only minimizes the
 % distortion measure approximately.
 % 
 % If the 'prob' argument is given, the distortion measure can be 
 % interpreted as an expected quantization error when the neighborhood 
 % function values give the likelyhoods of accidentally assigning 
 % vector j to unit i. The normal quantization error is a special case 
 % of this with zero incorrect assignement likelihood. 
 % 
 % NOTE: when calculating BMUs and distances, the mask of the given 
 %       map is used.
 %
 % See also SOM_QUALITY, SOM_BMUS, SOM_HITS.
 
 % Reference: Kohonen, T., "Self-Organizing Map", 2nd ed., 
 %    Springer-Verlag, Berlin, 1995, pp. 120-121.
 %
 %    Graepel, T., Burger, M. and Obermayer, K., 
 %    "Phase Transitions in Stochastic Self-Organizing Maps",
 %    Physical Review E, Vol 56, No 4, pp. 3876-3890 (1997).
 
 % Contributed to SOM Toolbox vs2, Feb 3rd, 2000 by Juha Vesanto
 % Copyright (c) by Juha Vesanto
 % http://www.cis.hut.fi/projects/somtoolbox/
 
 % Version 2.0beta juuso 030200
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% check arguments
 
 % input arguments
 if nargin < 2, error('Not enough input arguments.'); end
 
 % map
 M = sM.codebook;
 munits = prod(sM.topol.msize);
 
 % data
 if isstruct(D), D = D.data; end
 [dlen dim] = size(D);
 
 % arg1, arg2
 rad = NaN;
 normalize = 0;
 if nargin>2, 
   if isnumeric(arg1), rad = arg1;
   elseif ischar(arg1) & strcmp(arg1,'prob'), normalize = 0;
   end
 end
 if nargin>3, 
   if isnumeric(arg2), rad = arg2;
   elseif ischar(arg2) & strcmp(arg2,'prob'), normalize = 0;
   end
 end
 
 % neighborhood radius
 if isempty(rad) | isnan(rad), 
   if ~isempty(sM.trainhist), rad = sM.trainhist(end).radius_fin;
   else rad = 1; 
   end
 end
 if rad<eps, rad = eps; end
 
 % neighborhood  
 Ud = som_unit_dists(sM.topol); 
 switch sM.neigh, 
  case 'bubble',   H = (Ud <= rad);
  case 'gaussian', H = exp(-(Ud.^2)/(2*rad*rad)); 
  case 'cutgauss', H = exp(-(Ud.^2)/(2*rad*rad)) .* (Ud <= rad);
  case 'ep',       H = (1 - (Ud.^2)/rad) .* (Ud <= rad);
 end  
 if normalize, 
   for i=1:munits, H(:,i) = H(:,i)/sum(H(:,i)); end
 end
 
 % total distortion measure
 mu_x_1 = ones(munits,1);
 tdmu = zeros(munits,1);
 hits = zeros(munits,1);
 for i=1:dlen,
   x = D(i,:);                        % data sample
   known = ~isnan(x);                 % its known components
   Dx = M(:,known) - x(mu_x_1,known); % each map unit minus the vector
   dist2 = (Dx.^2)*sM.mask(known);    % squared distances  
   [qerr bmu] = min(dist2);           % find BMU
   tdmu = tdmu + dist2.*H(:,bmu);     % add to distortion measure
   hits(bmu) = hits(bmu)+1;           % add to hits
 end 
 
 % average distortion per unit
 admu = tdmu; 
 ind = find(hits>0);
 admu(ind) = admu(ind) ./ hits(ind);
   
 % average distortion measure
 adm = sum(tdmu)/dlen;
 
 return;
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%