function sD = som_denormalize(sD,arg2,arg3)

%SOM_DENORMALIZE Denormalize data.
%   
% sS = som_denormalize(sS,[comps])               
% D = som_denormalize(D,sNorm,[comps])               
%
%   sS = som_denormalize(sS) 
%   sS = som_denormalize(sS,[1:3 10]) 
%    D = som_denormalize(D,sM.comp_norm)
%    D = som_denormalize(D,sM,[1:3 10])
%
%  Input and output arguments ([]'s are optional): 
%   sS                The data to which the denormalization is applied.
%                     The modified and updated data is returned.
%            (struct) data or map struct
%            (matrix) data matrix (a matrix is also returned)
%   [sNorm]           The normalization(s) which are reverted. Cannot
%                     be used if a data/map struct is given as the data.
%            (struct) Normalization struct, or an array of such. 
%                     Alternatively, a map/data struct can be given 
%                     in which case its '.comp_norm' field is used 
%                     (see below).
%            (cell array) Of normalization structs. Typically, the
%                     '.comp_norm' field of a map/data struct. The 
%                     length of the array must be equal to data dimension.
%   [comps]  (vector) the components to which the denormalization is
%                     applied, default is [1:dim] ie. all components
%
% For more help, try 'type som_denormalize' or check out the helpdesk.
% See also SOM_NORMALIZE, SOM_NORM_VARIABLE, SOM_INFO.

%%%%%%%%%%%%% DETAILED DESCRIPTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% som_denormalize
%
% PURPOSE
%
% Undo normalizations of data structs/sets.
%
% SYNTAX
%
%  sS = som_denormalize(sS)
%  sS = som_denormalize(sS,comps)
%   D = som_denormalize(D,sNorm)
%   D = som_denormalize(D,sData)
%   D = som_denormalize(D,sData.comp_norm)
%   D = som_denormalize(D,sNorm,comps)
%
% DESCRIPTION
%
% This function is used to undo normalizations of data structs/sets. If a
% data/map struct is given, all normalizations in the '.comp_norm' field are
% undone and, thus, the values in the original data context are returned. If
% a matrix is given, the normalizations to undo must be given as the second
% argument. SOM_DENORMALIZE actually uses function SOM_NORM_VARIABLE to
% handle the normalization operations, and only handles the data struct/set
% specific stuff itself.
%
% Normalizations are always one-variable operations. In the data and map
% structs the normalization information for each component is saved in the
% '.comp_norm' field, which is a cell array of length dim. Each cell
% contains normalizations for one vector component in a
% struct array of normalization structs. Each component may have different
% amounts of different kinds of normalizations. Typically, all
% normalizations are either 'undone' or 'done', but in special situations
% this may not be the case. The easiest way to check out the status of the
% normalizations is to use function SOM_INFO, e.g. som_info(sS,3)
% 
% REQUIRED INPUT ARGUMENTS
%
%   sS                The data to which the denormalization is applied.
%            (struct) Data or map struct. The normalizations in the 
%                     '.comp_norm' field are undone for the specified 
%                     components.
%            (matrix) Data matrix. The normalization to undo must be
%                     given in the second argument.
%
% OPTIONAL INPUT ARGUMENTS
%
%   sNorm             The normalization(s) to undo. Can only be given
%                     if a data matrix is given as the first argument.
%            (struct) Normalization struct, or an array of structs, which
%                     is undone for all specified components. If the 
%                     '.status' field of the struct(s) is 'uninit', 
%                     the undoing operation is interrupted - it cannot be 
%                     done. Alternatively, the struct may be map or 
%                     data struct in which case its '.comp_norm' field 
%                     is used (see the cell array option below).
%            (cell array) In practice, the '.comp_norm' field of 
%                     a data/map struct. The length of the array 
%                     must be equal to the dimension of the given 
%                     data set (sS). Each cell contains the
%                     normalization(s) for one component. Only the
%                     normalizations listed in comps argument are
%                     undone though.
%
%   comps    (vector) The components which are denormalized.
%                     Default is to undo all components.
%
% OUTPUT ARGUMENTS
% 
%   sS                Modified and/or updated data.
%            (struct) If a struct was given as input argument, the
%                     same struct is returned with denormalized data and
%                     updated '.comp_norm' fields. 
%            (matrix) If a matrix was given as input argument, the 
%                     denormalized data matrix is returned.
% 
% EXAMPLES
%
%  To undo normalization of a data/map struct: 
%
%    sD = som_denormalize(sD); 
%    sM = som_denormalize(sM); 
%
%  To undo only a few selected components, use the comps argument: 
% 
%    sD = som_denormalize(sD,[1 3:5]); 
% 
%  To denormalize a set of values from a data set D (which must be 
%  of equal dimension as the data in sD): 
%
%    D = som_denormalize(D,sD); 
%  or 
%    D = som_denormalize(D,sD.comp_norm); 
%  only denormalize a few components
%    D = som_denormalize(D,sD,[1 3:5]); 
% 
%  Assuming you have a few values of a certain vector component (i)
%  in a vector (x) which you want to denormalize: 
%
%    xorig = som_denormalize(x,sD.comp_norm{i}); 
%  or using SOM_NORM_VARIABLE
%    xorig = som_norm_variable(x,sD.comp_norm{i},'undo');
%
%  To check out the status of normalization in a struct use SOM_INFO: 
% 
%    som_info(sM,3)
%    som_info(sD,3)
%
% SEE ALSO
%  
%  som_normalize      Add/apply/redo normalizations of a data struct/set.
%  som_norm_variable  Normalization operations for a set of scalar values.
%  som_info           User-friendly information of SOM Toolbox structs.

% Copyright (c) 1998-1999 by the SOM toolbox programming team.
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 2.0beta juuso 151199

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% check arguments

error(nargchk(1, 3, nargin));  % check no. of input arguments is correct

% sD
struct_mode = isstruct(sD);
if struct_mode, 
  switch sD.type
   case 'som_map', D = sD.codebook; 
   case 'som_data', D = sD.data; 
   otherwise, error('Illegal struct.')
  end
else 
  D = sD;
end
[dlen dim] = size(D);

% comps
comps = [1:dim];
if struct_mode, 
  if nargin>1, comps = arg2; end
else
  if nargin>2, comps = arg3; end
end
if iscell(comps) | isstruct(comps), 
  error('Invalid struct for comps.');
end
if isempty(comps), return; end
if size(comps,1)>1, comps = comps'; end  % make it a row vector

% sNorm
if struct_mode, sNorm = sD.comp_norm; 
elseif nargin>1 & (iscell(arg2) | isstruct(arg2)), sNorm = arg2; 
end
% check out the given normalization
% (and if necessary, copy it for each specified component)
if isstruct(sNorm),
  switch sNorm(1).type, 
   case {'som_map','som_data'}, csNorm = sNorm(1).comp_norm; 
   case {'som_norm'}, for i=comps, csNorm{i} = sNorm; end
   otherwise, 
    error('Invalid struct for sNorm.')
  end
elseif iscell(sNorm), 
  csNorm = sNorm; 
else
  error('Illegal value for sNorm.')
end

% check that csNorm and comps possibly agree
if max(comps) > length(csNorm), 
  error('Given normalizations does not match the components.')
end  
if length(csNorm) ~= dim, 
  error('Given normalizations does not match data dimension.')
end  


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% action

% remove the normalizations 
for i = comps, 
  len = length(csNorm{i});
  for j=len:-1:1, 
    sN = csNorm{i}(j); 
    if struct_mode, 
      if strcmp(sN.status,'done'), 
	[x,sN] = som_norm_variable(D(:,i), sN, 'undo'); 
	D(:,i) = x; 
	csNorm{i}(j) = sN; 
      end
    else
      D(:,i) = som_norm_variable(D(:,i), sN, 'undo'); 
    end
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% output 

if struct_mode, 
  switch sD.type
   case 'som_map', sD.codebook = D; 
   case 'som_data', sD.data = D; 
   otherwise, error('Illegal struct.')
  end
  sD.comp_norm = csNorm;
else
  sD = D;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



