%PRMAPPING Mapping class constructor
%
%  W = PRMAPPING(MAPPING_FILE,MAPPING_TYPE,DATA,LABELS,SIZE_IN,SIZE_OUT)
%  U = PRMAPPING(MAPPING_FILE,'untrained',PARS)
%  W = PRMAPPING(MAPPING_FILE,'combiner',PARS)
%
% DESCRIPTION
% A mapping/classifier object W is constructed. It points to the command
% MAPPING_FILE that is able to execute the mapping. It may be used to map a
% dataset A on another dataset B by B = PRMAP(A,W) or by training a mapping 
% using an untrained mapping U and a dataset A: W = PRMAP(A,U) or by modifying,
% (or combining) a mapping W with another mapping V: W_NEW = PRMAP(V,W);
% These operations may also be written as B = A*W, W = A*U or W_NEW = V*W.
%
% As a general rule for the case A is a cell array, B = A*W is executed
% for all elements in A, returning a cell array B: B{i} = A{i}*W. An
% exeception is the mapping type 'fixed_cell', see below.
%
% As PRTools contains many predifined mappings there is no need for the 
% starting user to define his own mappings. Advanced users may inspect
% simple examples like SIGM or SUBSC to see how they are constructed.
%
% MAPPING_FILE       name of the routine used for defining, training or 
%                    executing the mapping. Such a routine (e.g.
%                    'mapfile'), typically a classifier or a data mapping,
%                    should generate a mapping W or U, and should also be
%                    able to accept and execute the following types of calls, 
%                    generated by PRTools depending on the value of 
%                    MAPPING_TYPE:
%  - MAPPING_TYPE = 'untrained': An untrained mapping U is trained by 
%                    W = mapfile(A,U) in which U is typically defined by 
%                    U = mapfile([],PARS{:}) or by just U = mapfile. PRTools
%                    generates W = mapfile(A,U) if the user supplies
%                    V = A*U.
%  - MAPPING_TYPE = 'trained': A trained mapping W can be applied to a 
%                    dataset D by D = mapfile(B,W), resulting in a
%                    dataset D. PRTools generates this call if the user
%                    supplies D = B*W. If W is the result of training an 
%                    untrained mapping U by a dataset A it holds that
%                    D = B*(A*U).
%  - MAPPING_TYPE = 'combiner': A combiner mapping W is able to modify or
%                    combine a set of mappings V. PRTools calls V2 = V1*W
%                    as V2 = mapfile(V1,PARS{:}). If W would not have been
%                    a combiner then V2 = V1*W would have been stored as a
%                    sequential mapping. See SEQUENTIAL
%  - MAPPING_TYPE = 'fixed': D = A*W is executed by D = mapfile(A,PARS{:}).
%                    In practice there is not much of a difference between
%                    a trained and a fixed mapping. The first is found from
%                    data, the latter is defined directly by its parameters
%  - MAPPING_TYPE = 'fixed_cell': Like a fixed mapping. D = A*W is executed 
%                    by D = mapfile(A,PARS{:}). However, in this case A can
%                    be a cell array. It thereby overrides the rule that a
%                    cellarray applied to a mapping is executed element by
%                    element.           
% MAPPING_TYPE       String defining the type of mapping:
%                   'untrained', 'trained', "combiner' or 'fixed', see above.
%                    Default is 'untrained'. PRMAPPING(MAPPING_FILE,DATA) is
%                    equivalent to PRMAPPING(MAPPING_FILE,'untrained',DATA)
% DATA               Data, structure or cell array necessary for defining the
%                    mapping, e.g. the weights of a neural network. DATA is
%                    just used in the MAPPING_FILE for executing the mapping.
%                    For fixed and untrained mappings DATA can only be a
%                    cell array.
% LABELS             Array with labels to be used as feature labels for the
%                    dataset resulting by executing the mapping. So at least
%                    as many labels as defined by SIZE_OUT has to be supplied.
% SIZE_IN            Input dimensionality or size vector describing its shape,
%                    e.g. in case the input space is derived from an image.
%                    For a classifier SIZE_IN is the feature size.
% SIZE_OUT           Output dimensionality or size vector describing its
%                    shape, e.g. in case the output space should represent an
%                    image. For a classifier SIZE_OUT is the number of
%                    classes. Default is the number of labels in LABELS.
%                    SIZE_IN and SIZE_OUT are just used for error checking.
%                    If SIZE_IN is not supplied they are both set to 0 and 
%                    checking is skipped.
%
% Other parameter fields may be set to define the mapping further by
%
%	W = PRMAPPING(MAPPING_FILE, MAPPING_TYPE, DATA, LABELS, ...
%     'field1',V1,'field2',V2, ...)
% or by
%
%	W = PRMAPPING(MAPPING_FILE, MAPPING_TYPE, DATA, LABELS, ...
%     SIZE_IN, SIZE_OUT,'field1',V1,'field2',V2, ...)
%
% The following fields are possible (if not set defaults are supplied):
%
% SCALE               Output multiplication factor. If SCALE is a scalar all
%                     multiplied by it. SCALE may also be a vector with size
%                     as defined by SIZE_OUT to set separate scalings for each
%                     output.
% OUT_CONV            0,1,2,3 for defining the desired output conversion:
%                     0 - no(default), 1: SIGM, 2: NORMM or 3: SIGM and NORMM.
%                     These values are set by cnormc in case of 2-class
%                     discriminants (OUTCONV = 1) and by CLASSC
%                     (OUT_CONV = OUT_CONV+2) to convert densities and
%                     sigmoidal outputs to normalised posterior probabilities.
% COST                Classification costs in case the mapping defines a
%                     classifier. See SETCOST.
% NAME                String with mapping name
% USER                User definable variable
%
% All parameters are stored in fields corresponding to the above names.
% Parameter fields of a given mapping may also be changed by:
%
%	W = SET(W,'field1',V1,'field2',V2, ...)
%
% They may also be set by the routines SETMAPPING_FILE, SETMAPPING_TYPE, 
% SETDATA, SETLABELS, SETSIZE_IN, SETSIZE_OUT, SETSIZE, SETSCALE, SETOUT_CONV,
% SETCOST, SETNAME and SETUSER. Fields may be retrieved by
%
%	VARARGOUT = GET(W,'field1','field2', ...)
%
% or by the routines GETMAPPING_FILE, GETMAPPING_TYPE, GETDATA, GETSIZE_IN,
% GETSIZE_OUT, GETSCALE, GETOUTCONV, GETCOST, GETNAME and GETUSER. 
%
% SEE ALSO (<a href="http://37steps.com/prtools">PRTools Guide</a>)
% DATASETS, MAPPINGS, SEQUENTIAL

% Copyright: R.P.W. Duin, duin@ph.tn.tudelft.nl
% Faculty of Applied Sciences, Delft University of Technology
% P.O. Box 5046, 2600 GA Delft, The Netherlands

% $Id: mapping.m,v 1.6 2009/11/06 12:55:07 duin Exp $

function varargout = prmapping(mapping_file,mapping_type,data,labels,varargin)
    
w.mapping_file = [];
w.mapping_type = 'untrained';
w.data = {};
w.labels = [];
w.size_in = 0;
w.size_out= 0;
w.scale = 1;
w.out_conv = 0;
w.cost = [];
w.name = [];
w.user = [];
w.version = [];

w = class(w,'prmapping');
superiorto('double')
superiorto('prdataset')
superiorto('prdatafile')

if nargin == 0 %return empty mapping in case of no input parameters
	w.mapping_type = 'fixed';
	varargout = {w};
	return
end	
				 
if isstruct(mapping_file)
  % convert structure to mapping
  w = mapping_file;
  w = class(w,'prmapping');
  varargout = {w};
  return
end

			% remove these lines if everybody knows. They enable the
% 			% usage of the old mapping definition
% if ismapping(mapping_file) && nargin == 1 && nargout > 1
% 	varargout = mapping_old(mapping_file);
% 	return
% end

w.version = prtver;

if isa(mapping_file,'prmapping');
	if nargin > 1
		error('Redefinition of mapping not supported, use set()')
	else
		w = mapping_file; 
	end
	varargout = {w};
	return
end

if isempty(mapping_file) % return empty mapping
	w.mapping_type = 'fixed';
	varargout = {w};
	return
end

w = setmapping_file(w,mapping_file);

if nargin == 1 
	;
elseif nargin == 2
	if ischar(mapping_type)     % regular call has mapping type as second par.
		w = setmapping_type(w,mapping_type);
	else                       % takes care of untrained mappings defined by
		w = setdata(w,mapping_type); % prmapping(mfilename,{par1, par2, ...})
	end
else
	w = setmapping_type(w,mapping_type); % second par. is mapping type
	w = setdata(w,data);                 % third par. is data field
	if nargin > 3 
		w = setlabels(w,labels);           % possible fourth par. are labels
	end
	if nargin > 4 && ~isempty(varargin)   % if the next par is not a string
		if ~ischar(varargin{1})             % is not a string,
			w = setsize_in(w,varargin{1});   % it is the mapping input size
			varargin(1) = [];                % delete it
			                                 % if the next par is not a string
			if ~isempty(varargin) && ~ischar(varargin{1}) 
				w = setsize_out(w,varargin{1});% it is the mapping output size
				varargin(1) = [];              % delete it
			else                             % if not supplied
				w = setsize_out(w,size(labels,1)); % retrieve if from the labels
			end
		end
		if ~isempty(varargin)              % interpret all other parameters
			w = set(w,varargin{:});          % by the set command
		end
	end
end
% no batch processing for handling untrained classifiers
if strcmp(w.mapping_type,'untrained')
	w = setbatch(w,0);
end

varargout = {w};
% 
% function v = mapping_old(w);
% % 
% % This serves compatibility with old mapping calls to retrieve data
% %
% persistent OLD_MAPPING_CONSTRUCT
% if isempty(OLD_MAPPING_CONSTRUCT)
% 	OLD_MAPPING_CONSTRUCT = 1;
% 	warning(['Data retrieval by MAPPING will not be supported in future versions.', ...
% 	prnewline,'         Use GET instead.',prnewline])
% end
% 
% [k,c] = size(w);
% v = {w.data,w.labels,w.mapping_file,k,c,w.scale,[]};
% return
