%BAGC Bag classifier for classifying sets of object instances
%
%		[WBAG,WOBJ] = BAGC(A,OBJCLASSF,BAGINDEX,BAGCOMBC,BAGCLASSF,BAGLAB)
%		D = B*WBAG
%
% INPUT
%   A          Training dataset with object labels and bag indices 
%   B          Test Dataset with index list of bags, stored as label list 
%   OBJCLASSF  Trained or untrained object classifier, default QDC
%   BAGINDEX   String or a label_list_index defining in which label list
%              of A the bag indices are stored, default 2.
%   BAGCOMBC   Combiner for objects in a bag, default VOTEC
%   BAGCLASSF  Untrained classifier for bags, default FISHERC
%   BAGLAB     String or a label_list_index defining in which label list
%              of A the bag labels are stored. Objects with the same 
%              bag index should have the same bag label. 
%              Default is the current labeling of A
%
% OUTPUT
%   WBAG       Trained bag classifier
%   WOBJ       Trained object classifier
%   D          Classification matrix of bags in B
%
% DESCRIPTION
% This routine offers a classifier for bags (e.g. images) of objects
% (e.g. pixels) stored in a single dataset. The objects in the training 
% set A should have at least two labels: bag labels (the class of their bag)
% and bag indices, defining which objects belong to the same bag. These two
% label sets should be stored by the ADDLABELS command in the dataset A.
% Refer to the multi-labeling system (see MULTI_LABELING) offered by 
% PRTools. The current object labels of A can be the bag labels, but may
% also be different, e.g. true object labels.
%
% BAGINDEX should be a label_list_name or a label_list_index defining the 
% label list used for storing the bag indices that refer to the bag an 
% object belongs to. The same label_list_name or label_list_index should be
% used for defining the bags of the test objects in B.
%
% All objects in A are used to train the object classifier OBJCLASSF if it 
% is untrained. The current object labels are used for that. Classification 
% results of the objects in the same bag are combined by BAGCOMBC, which 
% can be any of the fixed combiners MEANC, PRODC, PERC, MAXC, etcetera.
% This results for every bag in a single confidence vector for the classes. 
%
% If an untrained bag classifier BAGCLASSF is supplied, the bag confidence
% vectors are used to train a bag classifier.
%
% New bags, organised in a dataset like B, with the proper bag indices per
% object stored in a label list with the same name or label_list_index as 
% used in A, can be classified by the bag classifier WBAG. 
%
% If no bag classifier BAGCLASSF was defined during training, just the
% results of the object classifier WOBJ are returned combined by BAGCOMBC
% over the objects in the same bag in B. In this case the final result is
% identical to B*(A*WOBJ)*BAGCC([],BAGCOMBC), provided that A has class
% labels and B is labeled by its bag indices.
%
% SEE ALSO
% DATASETS, MAPPINGS, MULTI_LABELING, BAGCC, LOSO,
% DATASET/ADDLABELS, DATASET/CHANGELABLIST

% Copyright: R.P.W. Duin, r.p.w.duin@37steps.com
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands

function [out1,out2] = bagc(a,objclassf,bagindex,bagcombc,bagclassf,baglab)

if nargin < 6 | isempty(baglab),    baglab = []; end
if nargin < 5 | isempty(bagclassf), bagclassf = []; end
if nargin < 4 | isempty(bagcombc),  bagcombc  = votec; end
if nargin < 3 | isempty(bagindex),  bagindex  = 2; end
if nargin < 2 | isempty(objclassf),  objclassf  = qdc; end

if nargin < 1 | isempty(a)
	% define the mapping
	wset = prmapping(mfilename,'untrained',{objclassf,bagindex,setcombc,bagclassf,baglab});
	out1 = setname(wset,'Set classifier');

elseif isuntrained(objclassf) | nargin > 2 | ~strcmp(getmapping_file(objclassf),mfilename)
	% train the mapping (classifier)

	% we need datasets with at least 1 object per class and 2 classes
	isvaldset(a,1,2);
	
	% if the object classifier is untrained, train it, else use it
	if isuntrained(objclassf)
		wobj = a*objclassf;
	else
		wobj = objclassf;
	end
	
	if ismapping(bagclassf) & isuntrained(bagclassf)
		
		% if the bag labels are not given, 
		% use the objcts labels for the bags too
		if isempty(setlab), setlab = curlablist(a); end
	
		% classifiy the dataset and change labeling to bag index
		x = changelablist(a*wobj,setindex);
		
		% avoid empty bags
		x = setlablist(x);
	
		% combine object results to bag results
		d = bagcc(x,bagcombc);
	
		% change to bag labels
		d = changelablist(d,baglab);
	
		% train bag classifier
		bagclassf = d*bagclassf;
		
		% get outputlabels
		labels_out = getlabels(bagclassf);
		
	else
		labels_out = getlabels(wobj);
	end
	
	% store all what is needed for execution in the mapping
	out1 = prmapping(mfilename,'trained',{wobj,bagcombc,bagclassf,bagindex,baglab}, ...
		labels_out, size(a,2),size(labels_out,1));
	
	% prevent batch execution
	out1 = setbatch(out1,0);
	
	% return the object classifier as well
	out2 = wobj;
	
else % here we are for execution
		
	% the mapping is stored in objclassf
	w = getdata(objclassf);
	
	% save current lablist
	curlist = curlablist(a);
	
	% use the bag index for the test set if supplied
	if ~isempty(w{4}), testset = changelablist(a,w{4}); end
	
	% classify test set by the object classifier
	d = testset*w{1};
		
	% avoid empty bags
	d = setlablist(d);
	
	% combine objects in the same bag
	d = bagcc(d,w{2}); 
	
	% reset lablist for classification matrix
	d = changelablist(d,curlist);
	
	% apply the set classifier, if defined
	if ~isempty(w{3}), d = d*w{3}; end
	
	% that is it, define class labels as feature labels
	out1 = setfeatlab(d,getlabels(objclassf));
	
end
	
	
	
	
	
	